-
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
Safer callback parameter checking #16726
Comments
Actually, it's easy to build a more minimal reproduction of the issue here: declare let foo: { a: number };
declare function bar<T>(a: T, b: () => T): void;
bar(foo, () => ({ a: 1 })); // As expected, this is working
bar(foo, () => ({ a: 1, b: 2 })); // Unexpected, this should be an error So it seems that generics aren't passed down to callbacks in TS 1.4? Maybe there is an issue already open for that? |
This has to do with the assignability of types... When you have a generic like this, that is in to positions being inferred, TypeScript has to try to figure out what the minimum type is and if both the positions are assignable. This in this case they are both assignable to the type If either of the values were not assignable to each other, then you would have an error: declare let foo: { a: number };
declare function bar<T>(a: T, b: () => T): void;
bar(foo, () => ({ a: 1 })); // As expected, this is working
bar(foo, () => ({ a: 1, b: 2 })); // Not an error because types are assignable to each other
bar(foo, () => ({ b: 1 })); // Throws an error The excess properties are somewhat "surprising" but are valid given the structural typing system. TypeScript used to play a bit looser with this, but now detects excess properties when there is a direct type assignment. For example, this fails: bar(foo, (): { a: number; } => ({ a: 1, b: 2 })); // Type not inferred, throws error If you let TypeScript guess at your intent, sometimes TypeScript may surprise you. |
Thank you for the answer. I'm still wondering if there is room for improvements here, or if this behavior is a fundamental consequence of Typescript structural type system. What I find puzzling is that the minimal example is working perfectly fine without the indirection of the callback: interface Foo { a: number }
declare function bar(a: Foo): void
declare function barWithCallback(a: () => Foo): void I find confusing that replacing a value of type As you point out @kitsonk, it's possible to enforce a stricter object type checking by putting an explicit annotation when calling the |
@mquandalle any difference between this and #12632 ? |
@RyanCavanaugh Thanks for pointing out this issue, I wasn't able to find it when searching for it. Closing in favor of #12632. |
TypeScript Version: 2.4.1-insiders.20170615
Edit: I've written a more minimal reproduction of the issue below
Following up on the examples of #12769, we have the following code which is working as expected:
However if we change the
update
signature to accept a spec factory, ie a parameter of type() => UpdateSpec<T>
instead of justUpdateSpec<T>
, the above error isn't triggered anymore:The text was updated successfully, but these errors were encountered: