-
Notifications
You must be signed in to change notification settings - Fork 12.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Variadic element of tuple-like intersection types are spreading incorrectly #40945
Comments
Unintuitive, yes; not as good as we could do, yes; but “incorrect” is somewhat debatable. (As an aside, this issue led to a great conversation about whether Out of curiosity, since there are 4 👍 on an issue that seems somewhat arcane, is this coming up in practice somewhere? |
I was building type-level programming library since TS 4.1 finally added recursive conditional type alias. But after few hours, I encountered this issue and talked with others in twitter for a few days. That 👍seems to be added by people I know or discussed with me about this. |
I agree on that T1 is not being incorrect, sorry for misusing word. However, I think we all agree on that ( 3 | 2 | 1 )[] is not a proper or useful typing at all at this point since some important informations are discarded and it might cause some unexpected problems. 🙂 (Sorry for loose formatting, I wrote this comment with my mobile phone...) |
Similar scenario for me. I was trying to map nested tuple types. |
This also becomes an array type, even though both sides of the intersection were tuples to begin with: type X = [...[1, 2] & [1, 2 | 3]]
// ^? type X = (2 | 1)[] |
Actually, this is also broken I had a similar "issue" when trying to get a tuple back from a tuple augmented with other properties. Investigation led me to the discovery that even You will find bellow my different attempts at getting the tuple back. Explicitly iterating over the numeric keys worked but I was surprised I had to go this far. type A = [1,2,3] & { foo: unknown };
// -> (3 | 1 | 2)[]
type B = [...A]
// -> { [x: number]: 3 | 1 | 2 }
type C = { [K in keyof A as K extends number ? K : never]: A[K] }
// -> [2 | 1 | 3]
type D = CloneTuple<A>
type CloneTuple<T extends unknown[], R extends unknown[]=[]> =
T extends [infer A, ...infer Rest]
? CloneTuple<Rest, [...R, A]>
: R
// -> [1, 2, 3]
type E = ToTuple<A>
type ToTuple<
T extends unknown[],
L extends number=T['length'],
C extends number = 0,
R extends unknown[]=[]
> = C extends L ? R : ToTuple<
T,
L,
[1,2,3,4,5,6,7,8,9,10][C],
[...R, T[C]]
> |
TypeScript Version: 4.0.3
Search Terms: variadic tuple, variadic element, intersection type, tuple-like type
Code
Expected behavior: for
T1
, I expected it to be[]
(empty tuple type) and forT2
, I expected it to be[1, 2, 3]
.Actual behavior: Both
T1
andT2
became Array rather than tuple somehow. (T1
is deduced tonever[]
,T2
is deduced to(3 | 1 | 2)[]
)detailed explanation
In some perspective,
unknown
could be recognized as type of all types. Therefore,[unknown]
is type of all type-level 1-tuples and intuitively,unknown[]
is type of all type-level n-tuples.So
[] <: unknown[]
is true (i.e. all empty type-level tuple is subtype of all type-level n-tuples) and you can check it simply with this code:However, in spite of the fact that
[]
is subtype ofunknown[]
therefore[] & unknown[]
is actually[]
, variadic element of[] & unknown[]
somehow spreads asnever[]
, which is incorrect and unintuitive.Playground Link: Playground
The text was updated successfully, but these errors were encountered: