-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Generic type sometimes returns never instead of actual template parameter type #41778
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
Comments
@ahejlsberg shorter and with distributivity removed enum E { A, B }
type Classify<Left, Right> = [Left] extends [Right] ? [Right] extends [Left] ? [Left, '==', Right] : [Left, '<:', Right] : [Right] extends [Left] ? [Left, ':>', Right] : [Left, '!=', Right];
// M: [E.A, 1, never]
type M = Classify<E.A, 1>; I would suspect this is caused by the assignability/subtyping relationship difference for number/enum comparisons -- do we need to consistently use one or the other when applying the narrowings in the conditional type branches? |
The culprit is this rule we have for the assignable relation (from comment in So, we consider Not sure what we can do here. |
The spitballed solution would be to say that We'd be interested to evaluate a PR for breaks. Presumably this could be a bugfinder -- |
I think no. It will be more usefull if enums are simply union of literals. Nothing more. |
We encountered this issue over at socketio/socket.io#3833. Here's another minimized bug reproduction: enum Enum {
NAME = "name",
WRONG_NAME = "wrong name"
}
type Name = "name";
type NameOrNull<N> = N extends Name ? N : null;
// Sanity checks:
type test1 = NameOrNull<"name">; // returns type `"test"`
type test2 = NameOrNull<"wrong name">; // returns type `null`
type test3 = Enum.NAME extends Name ? Enum.NAME : null // returns type `Enum.NAME`
type test4 = NameOrNull<Enum.WRONG_NAME>; // returns type `null`
// Unexpected behavior:
type test5 = NameOrNull<Enum.NAME>; // returns type `never`, but expected type `Enum.NAME` |
So then this is a duplicate/related to #21998, I think. Why can't we have the intersection of an enum and the wider literal it comes from just be the enum? Especially for string enums, which doesn't have the bitflag craziness to deal with? |
TypeScript Version: 3.6+
Search Terms: enum, extends, never, template parameters
Code
Actual at 3.6+
Expected and before 3.6
The text was updated successfully, but these errors were encountered: