-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
parameters: presume generics over any
#14078
Comments
This is similar to what F# does (where it is known as automatic generalization). |
Assuming this isn't just "Recognize the identity function", this needs a description of how it might plausibly work |
@RyanCavanaugh The goal is to ensure that the types of function arguments (which will be available at the call site) can participate in inference of the return type. Here's a rough gist of the idea. Contextual type inference for functions needs to change so that the type inferred for function f(a, b, c) {
if (10 > 11) {
return a;
}
if (192 - 7 < 11) {
return b;
}
return c;
}
const { s, n, d } = { s: "Hello", n: 10, d: new Date() };
const result = f(s, n, d); // any Is identical to what is inferred in the following snippet: function f<T1, T2, T3>(a: T1, b: T2, c: T3) {
if (10 > 11) {
return a;
}
if (192 - 7 < 11) {
return b;
}
return c;
}
const { s, n, d } = { s: "Hello", n: 10, d: new Date() };
const result = f(s, n, d); // string | number | Date As a starting point, let's say we simply desugar all function declarations so that every parameter without an explicit type annotation corresponds to a generic type parameter in the final type signature of the function. // The following:
function foo(a: number, b: string, c) { return c; }
// Is now equivalent from a type system perspective to:
function foo<T1>(a: number, b: string, c: T1) { return c; } When called without type arguments, this behaves the same as The tricky part is figuring out how this interacts with explicitly generic functions. Because we don't have HKTs, and type signatures can't be partially applied, it is hard to figure out what type signature should be constructed for this function: function prop<V>(object, key): V { /* ... */ } Do the inferred generic arguments simply get appended to the function's type signature? Because you can't partially supply generic type arguments, this results in incovenience at the call site: // If the type system treats the above as:
function prop<V, T1, T2>(object: T1, key: T2): V { /* ... */ }
// Calling the function becomes annoying:
const val1 = foo({ h: "ello" }, "h"); // Inferred as any
const val2 = foo<string>({ h: "ello" }, "h"); // Can't do this, passing type args is all-or-nothing
const val3 = foo<string, {}, string>({ h: "ello" }, "h"); // You have to pass mysterious type arguments you never explicitly declared Some possible solutions:
Don't really have any great ideas on this front. I'm also probably missing a bajillion edge cases and interactions with other language features, but that's the rough idea. Some other thoughts:
|
Thanks for helping elaborate, @masaeedu. :) To add to your post a bit:
Partial application of generics sounds like #14400, while HKTs seemed the topic of #1213. |
Closing in favor of #17428. |
TypeScript Version: any
Code
Expected behavior:
TS should be able to save parameter types (where unspecified) into generics so as to improve inference.
Actual behavior:
Things type-check while TS should have enough info to conclude they shouldn't.
Perhaps this could make for a compiler flag?
The text was updated successfully, but these errors were encountered: