You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[1,2][any]// 1 | 2[1,2][never]// never ----or Error: A tuple type cannot be indexed with `never`.----// is the similar reasoning as:[1,2][2]// Tuple type '[1, 2]' of length '2' has no element at index '2'.[1,2][-1]// A tuple type cannot be indexed with a negative value.
UPDATE:
or Error: A tuple type cannot be indexed with never
is strike out, as the expression [1, 2][never] is value as:
any and number is a superset of 0 and 1, so yielding 'a' | 'b' make sense as the category is mapped correctly. number is narrowed to 0 and 1 thus the result is the union of values.
(UPDATE: or may be not? Maybe resolving to 'a' | 'b' | undefined make more sense? Or since any and number contains invalid index types such as negative number or non-number, it should be invalid?)
But never supposed to be the bottom type of everything. From handbook:
The never type is a subtype of, and assignable to, every type; however, no type is a subtype of, or assignable to, never (except never itself). Even any isn’t assignable to never.
Union order is a pure implementation detail: It depends on the order the constituent types are first instantiated by the compiler and thus can change depending on the surrounding code, the order in which files are compiled (in a multi-file project) or even with different compiler settings. For all intents and purposes, you should treat it as random.
I think you could argue either way whether the "correct" bound on that type is [1, 2] or never, but plainly both are sound. Absent a more concrete argument for changing it, I don't see what the goal is here.
I think your logic and my logic are both correct, and both create correct upper bounds.
Generally we've found it's disruptive to just go change stuff without being able to point to a code example and say "We made this work now" as justification for making those changes. Inevitably, changes cause breaks, and people want to know why you broke them, and there should be a better answer than "Someone used ∈ correctly"
No problem. I understand that changes could break someone else's code.
I understand that TypeScript need to make trade-offs, balance between usability vs soundness.
It might even be too late to change now, but things like these make the type system harder to reason, thus make it harder to understand and write correct (type-level) code.
I'm going to have this logic in the At<A, N> type in type-plus. i.e.:
typeR=At<[1,2,3],never>// never
This way, there is at least some way to obtain that behavior.
Activity
Andarist commentedon Mar 18, 2023
This happens for all index signatures, for example:
isApplicableIndexTypehere just ends up callingisTypeAssignableTo(source, target)and... well,neveris assignable to everything.unional commentedon Mar 18, 2023
Yes,
neveris assignable to everything:The question is what does
Array<T>[never]mean.playground
anyandnumberis a superset of0and1, so yielding'a' | 'b'make sense as the category is mapped correctly.numberis narrowed to0and1thus the result is the union of values.(UPDATE: or may be not? Maybe resolving to
'a' | 'b' | undefinedmake more sense? Or sinceanyandnumbercontains invalid index types such as negative number or non-number, it should be invalid?)But
neversupposed to be the bottom type of everything. From handbook:So to me yielding
'a' | 'b'doesn't sound right.unional commentedon Mar 19, 2023
btw, while union order doesn't matter,
[1, 2, 3][number]yields2 | 1 | 3instead of1 | 2 | 3is kind of weird.Playground yields
3 | 1 | 2instead...Both Playground and local in my computer (Windows 7) are using TypeScript 5.0.2.
playground
fatcerberus commentedon Mar 19, 2023
Union order is a pure implementation detail: It depends on the order the constituent types are first instantiated by the compiler and thus can change depending on the surrounding code, the order in which files are compiled (in a multi-file project) or even with different compiler settings. For all intents and purposes, you should treat it as random.
RyanCavanaugh commentedon Mar 20, 2023
I don't follow the logic in the OP at all.
[1, 2][keyof [1, 2]]is legalneveris a legalkeyof [1, 2][1, 2][never]is legal tooI think you could argue either way whether the "correct" bound on that type is
[1, 2]ornever, but plainly both are sound. Absent a more concrete argument for changing it, I don't see what the goal is here.unional commentedon Mar 21, 2023
Yes,
neveris a legal value ofkeyof [1, 2]=(0 | 1)asneveris considered as the "empty union"().And yes, the question should focus on what it resolves/bounds to.
The problem and confusion is that the current behavior does not map logically.
Consider type as set:
When mapped using "functor"
[1, 2][N], the result is:That means:
is transformed to
meaning
never, which is a bottom type of all, is mapped to a larger set then its superset.That's why
[1, 2][never] // 1 | 2should be incorrect.It should resolve to
nevertypescript-bot commentedon Mar 24, 2023
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.
unional commentedon Mar 24, 2023
Reopen?
RyanCavanaugh commentedon Mar 24, 2023
I'd consider it, but again, a motivating scenario is needed given that the current result is still a correct upper bound.
unional commentedon Mar 24, 2023
Do you think my reasoning here is correct? #53345 (comment)
That tries to reason that returning
1 | 2is the incorrect behavior.RyanCavanaugh commentedon Mar 24, 2023
I think your logic and my logic are both correct, and both create correct upper bounds.
Generally we've found it's disruptive to just go change stuff without being able to point to a code example and say "We made this work now" as justification for making those changes. Inevitably, changes cause breaks, and people want to know why you broke them, and there should be a better answer than "Someone used ∈ correctly"
unional commentedon Mar 24, 2023
No problem. I understand that changes could break someone else's code.
I understand that TypeScript need to make trade-offs, balance between usability vs soundness.
It might even be too late to change now, but things like these make the type system harder to reason, thus make it harder to understand and write correct (type-level) code.
I'm going to have this logic in the
At<A, N>type in type-plus. i.e.:This way, there is at least some way to obtain that behavior.