You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
error TS2345: Argument of type 'typeof MySubClass' is not assignable to parameter of type 'typeof MyClass'.
Type 'MySubClass' is not assignable to type 'MyClass<T>'.
Types of property 'doIt' are incompatible.
Type '(data: Readonly<II2>) => void' is not assignable to type '(data: Readonly<T>) => void'.
Types of parameters 'data' and 'data' are incompatible.
Type 'Readonly<T>' is not assignable to type 'Readonly<II2>'.
Property 'foo' is missing in type 'Readonly<T>'.
This is working as intended and is an effect of #16368. The type checker is pointing out that it is not safe to treat the doIt(data: Readonly<II2>) method in MySubClass as the more general doIt(data: Readonly<T>) in MyClass<T>. Effectively, you can't treat a method that expects the specific type II2 as a method that accepts any type that derives from MyInterface.
This feels like it limits generics to the point where they're hardly useful anymore...
What we're trying to model is a "Model" class that wraps some data handled by a JSON API:
interfaceIModelData{href : string;// All models have an href}classModelBase<DataTypeextendsIModelData>{persist(data : Readonly<DataType>){returncallToServer(data['href'],data);}}interfaceIUserDataextendsIModelData{username : string;}classUserextendsModelBase<IUserData>{}
What is the correct way to model this in TypeScript that allows proper typechecking?
One way to model it is to have a non-generic base class:
interfaceIModelData{href : string;// All models have an href}abstractclassModelBase{abstractpersist(data: IModelData): void;}classGenericBase<DataTypeextendsIModelData>extendsModelBase{persist(data : Readonly<DataType>){returncallToServer(data['href'],data);}}interfaceIUserDataextendsIModelData{username : string;}classUserextendsGenericBase<IUserData>{}functionfn(arg: typeofModelBase){};fn(User);
Another way is to not use typeof ModelBase but instead write out the actual factory type:
interfaceIModelData{href : string;// All models have an href}classModelBase<DataTypeextendsIModelData>{persist(data : Readonly<DataType>){returncallToServer(data['href'],data);}}interfaceIUserDataextendsIModelData{username : string;}classUserextendsModelBase<IUserData>{}functionfn(arg: new()=>ModelBase<IModelData>){}fn(User);
With either approach you're ensuring that the arg parameter of fn is a contract that is satisfied by every subclass constructor function.
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.
Activity
ahejlsberg commentedon Aug 28, 2017
This is working as intended and is an effect of #16368. The type checker is pointing out that it is not safe to treat the
doIt(data: Readonly<II2>)method inMySubClassas the more generaldoIt(data: Readonly<T>)inMyClass<T>. Effectively, you can't treat a method that expects the specific typeII2as a method that accepts any type that derives fromMyInterface.dpogue commentedon Aug 28, 2017
This feels like it limits generics to the point where they're hardly useful anymore...
What we're trying to model is a "Model" class that wraps some data handled by a JSON API:
What is the correct way to model this in TypeScript that allows proper typechecking?
ahejlsberg commentedon Aug 29, 2017
One way to model it is to have a non-generic base class:
Another way is to not use
typeof ModelBasebut instead write out the actual factory type:With either approach you're ensuring that the
argparameter offnis a contract that is satisfied by every subclass constructor function.mhegazy commentedon Sep 12, 2017
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.