Home > Software engineering >  Why `T` has been infered into two different types?
Why `T` has been infered into two different types?

Time:03-22

assume we have such code snippet

function test<T extends unknown[]>(source: [...T], b: T) {
  return b;
}
const arg = [1, 'hello', { a: 1 }] 

const res = test(arg, [])
const res1 = test([1, 'hello', { a: 1 }], [])

res has type (string | number | {a: number;})[] but res1 has type [number, string, {a: number;}]

I am wonder why the T has been infered two different type.

CodePudding user response:

This is because TS "widens" arg to (string | number | { a: number}), this is because arg is mutable, so you can change the value in-between the time you declare it and the time you call it in test. It simply infers it is an array that you might add elements to. So TS can only guarantee that it might have these elements, but cannot guarantee it's final shape.

While in res1 the parameter is basically immutable, so TS can guarantee it's type to [number, string, {a: number;}]. To prevent this narrowing you have to make arg readonly, or explicitly type it.

const arg1 = [1, 'hello', { a: 1 }] as const
const arg2: [1, 'hello', { a: 1 }] = [1, 'hello', { a: 1 }]

View examples on TS Playground

CodePudding user response:

In your function you used Variadic Tuple Types

With this feature, the argument type is inferred to be a Tuple.

If you extract the argument to a separate variable, it is inferred to be an Array (unless you use a as const assertion to force it to be a Tuple).

  • Related