I have the following typescript code:
const myObject = {
foo: ['a', 'b', 'c']
}
type MyType = typeof myObject.foo extends [...infer Content] ? string : boolean
And MyType results in type string
as expected.
But if I change the code like this:
...
type MyType = typeof myObject.foo extends [infer First, ...infer Tail] ? string : boolean
MyType now becomes boolean
. Why?
Why does it extend in the first case but not in the latter?
CodePudding user response:
First use case:
const myObject = {
foo: ['a', 'b', 'c']
}
type MyType1 = string[] extends [...infer Content] ? string : boolean
[...infer Content]
- means that tuple might have 0 or 1 or more elements. No restriction at all.
Hence, since string[]
is an array without explicit length (is not a tuple) you are getting string
.
Second case
type MyType2 = string[] extends [infer First, ...infer Tail] ? string : boolean
[infer First, ...infer Tail]
- mean that your tuple should have at least one element, because of First
.
Because you are checking myObject.foo
which is basically stirng[]
, TS is not allowed to make any assumptions about string[]
length. string[]
is a mutable array.
Try to make myObject
immutable.
const myObject = {
foo: ['a', 'b', 'c']
} as const;
// string
type MyType1 = typeof myObject.foo extends readonly [...infer Content] ? string : boolean
//string
type MyType2 = typeof myObject.foo extends readonly [infer First, ...infer Tail] ? string : boolean
Now, both MyType
's are strings
.
SUMMARY
['a', 'b', 'c']
is infered as string[]
because, like I said it is an array and not a tuple.
If you want it to make a tuple, you can use ['a', 'b', 'c'] as const
.