1

Here is the code:

const func = (...args: [string, {a: true}] | [number, {b: true}]) => {
  if (typeof args[0] === 'string') {
    return args[1].a;
  } else {
    return args[1].b;
  }
}

And typechecking failes to determine the shape of args variable. Is it somehow possible to do?

I expect that the example code doesn't show any TS errors

7
  • 3
    The type of args is not a discriminated union because string and number are not valid types for a discriminant (which must be a unit/singleton/literal type). There's no built-in method to narrow non-discriminated unions by checking properties. You could write your own type guard functions and use them, like this perhaps. Does that fully address your question? If so I could write up an answer explaining; if not, what am I missing? Please mention @jcalz if you reply to notify me. Commented Oct 31, 2022 at 20:00
  • @jcalz It never crossed my mind that we can’t use primitive types as a discriminant. Learned something new today. Is this something documented by TypeScript? I tried looking at their docs and can’t find this being mentioned. Commented Nov 1, 2022 at 7:02
  • @Terry If I write up an answer here I will make sure to include links to sources (ms/TS#48500 is a reasonable place to start); right now I'm waiting to hear back from the OP on whether I'm missing anything about the question before I expend too much effort on it. Commented Nov 1, 2022 at 13:28
  • @jcalz yes, you exactly answered my question! I thought primitive types could not be used as a discriminated type. Thanks! Commented Nov 1, 2022 at 19:09
  • 1
    I don't like to poach points from people if I can help it. Maybe @caTS will edit their answer with whatever you want to see from mine. Commented Nov 1, 2022 at 19:15

1 Answer 1

2

You could use type predicates to "artificially" narrow the type of arg:

function firstIsString(arg: [unknown, unknown]): arg is [string, unknown] {
    return typeof arg[0] === "string";
}

const func = (...args: [string, { a: true }] | [number, { b: true }]) => {
    if (firstIsString(args)) {
        return args[1].a;
    } else {
        return args[1].b;
    }
};

Playground

Sign up to request clarification or add additional context in comments.

3 Comments

Unfortunately there is a type error at the line firstIsString(args), no?
@Terry Whoops, it didn't error when I first typed that in. It looks like a generic is not necessary either.
Wow, interesting workaround. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.