-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Allow use of infer
in the type parameter of a type declaration
#52791
Comments
I doubt this would meet the bar for inclusion but we can listen for feedback. There'd probably have to be some new syntax for this, since type J = string;
// RHS "J" here must refer to outer J, not infer J
type M<T, U extends (T extends {a: infer J } ? J : number)> = J; type ConstructorParameters<T extends abstract new (...args: infer P) => any> = P; This is sort of confusing from a lexical scoping perspective. |
I don't completely follow the counter-example.
Regarding scoping, if This feels like a logical progression following the addition of "extends Constraints on infer Type Variables" added in 4.7. When you use a parameterized type it is already a kind of conditional. The difference is if you don't satisfy the condition, you get a compile error rather than an alternate type. |
I'm on board with this bigtime. I actually just asked a question about this exact thing on StackOverflow yesterday and got a comment pointing me here. I absolutely think this makes sense as a feature. When I learned about the |
@RyanCavanaugh I don't think your example raises a problem at all. That's just basic scoping and variable shadowing stuff, isn't it? It looks like there's essentially a little scope created by the conditional statement, within the parentheses as you've written it:
I don't think I'd expect that
In this example, the
No TS errors. I think this particular point is moot. It's confusing only if you choose conflicting type names, you know? I don't think it's confusing for the parser. |
This would be useful elsewhere too: type Wrapper<T> = {
wrapped: T;
}
function unwrap<W extends Wrapper<V>, V = W extends Wrapper<infer U> ? U : never>(w: W): V {
return w.wrapped;
}
const result = unwrap({wrapped: 42}); When this would be preferred (maybe even without function unwrap<W extends Wrapper<infer V>, V>(w: W): V {
return w.wrapped;
} |
FWIW implementing this might change behavior since it requires TS to infer type variables from a constraint, which, at present, it doesn't do at all: function foo<U, T extends Array<U>>(array: T): Array<NonNullable<U>> {
// ...
};
const food: string[] = [ "foo", "bar" ];
foo(food); // infers U = unknown From what I understand, this is because inferring from constraints often produces bad inferences. |
Suggestion
For many type declarations, it shouldn't be necessary to use a conditional type which repeats a constraint already found in type parameter.
For example, instead of:
This would be better expressed as:
🔍 Search Terms
infer type parameter conditional type type declaration
✅ Viability Checklist
My suggestion meets these guidelines:
⭐ Suggestion
See above
📃 Motivating Example
TypeScript's own built-in types have other examples where constraints are repeated in both a type parameter and conditional type. I've also seen cases where developers just don't want to repeat constraints, so they define:
And then incorrect usage results in a type of
never
, rather than an error.💻 Use Cases
The text was updated successfully, but these errors were encountered: