-
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
Covariance on generic return type with constraints is not respected anymore (TypeScript 2.4.2) #17509
Comments
This is working as intended and is a result of the stricter checks introduced in #16368. In your example, the function foo<T extends IMyObject>(name: string): T {
// T could be any type that derives from IMyObject, but there's no way
// to discover what T is because it isn't used in a parameter type.
} The interface IMyDerived extends IMyObject {
foo: string;
bar: number;
}
let derived = factoryFunc<IMyDerived>("hello"); // How could function know what to do? In fact, the only call to It may be that you meant for the type parameter to be declared on the type IMyFactoryType<T extends IMyObject> = (name: string) => T; This would make a lot more sense, but it would of course also require you to specify a type argument when you reference the type. |
I gave more tought about this and you are right, there's really no way to discover what T was in the code above; I was indeed using the generic return type in a hacky way to avoid an explicit type assertion in the code. In short the problem arose from a function that call some external (non typed) JavaScript library that creates wrappers for some service endpoints for which I wrote a TypeScript code generator (just service interfaces and DTOs). I was using the generic type on the return value to avoid an extra type assertion in the code, which I'll admit is not really a best practice. I got rid of the problem adding an 'extra layer' that handles factory functions discovering and the type assertions in a more correct way. Now I have something like this: // Ok I'll admit this is a hack to avoid an explicit type assertion in the code.
// The correct code should have been:
// const f = getServiceFactory("service1") as (name: string) => MyService1;
// This is very ugly to write, so I did this:
// const f = getServiceFactory<MyService1>("service1"); // ofc you can create e service and assert it to the wrong type... pay attention
function getServiceFactory<T extends IMyService>(name: string): (name: string) => T {
let myServiceFactoryFunc: (name: string) => IMyService; // <- explicitly return the common interface
myServiceFactoryFunc = getTheFactoryFuncFromJS(name); // some code to retrieve an instace of a factory function from 'name'
return myServiceFactoryFunc as (name: string) => T;
} Closing the issue, thanks for looking into it! |
Sorry if this isn't the right place to put this, but if the function does have a parameter should it be inferable? For example redux has the typing: interface Action {
type: any;
}
interface Dispatch {
<A extends Action>(action: A): A;
} With strict set to true the following fails to compile with something along the lines const dispatch: Dispatch = (action: Action) => action; |
TypeScript Version: 2.4.1 / 2.4.2 / nightly (2.5.0-dev.201xxxxx)
Code
Try it out compiling with the lastet TypeScript installment and with the previos 2.4.0 version.
Expected behavior:
everything should compile and work without errors
Actual behavior:
compiling with TypeScript 2.4.1+ I get the following error:
Workaround
disable the new strict checking on generics with 'noStrictGenericChecks' in tsconfig.json
The text was updated successfully, but these errors were encountered: