Reputation: 58732
Please see the code here It is in typescript, but due to the similarity with C# may be it is applicable to it too.
export class Promise<T> {
}
export interface IId{
id:()=> string;
}
class Service {
get(id:string): Promise<IId> { return }
}
export interface IUser extends IId{
name: string
}
export interface IUserService{
test:(d:string) => Promise<IUser>;
}
class UserService implements IUserService{
constructor(private srv: Service){}
test(d:string):Promise<IUser> {
return this.srv.get("");
}
}
say, I have a framework service function get
which returns a promise of type IId
. In my custom class, I have a method, which is defined to return a promise of type IUser
. I made a mistake by returning this.srv.get("")
, which returns Promise<IId>
. But that should not be compatible with Promise<IUser>
as IUser is expecting a name
field. Why there is no error?
I am not familiar with C# generics, and is this what called contravariance
. Read some articles but couldn't wrap my head around it.
Upvotes: 0
Views: 204
Reputation: 221282
Your Promise
type is empty and doesn't use T
, both of which are really big problems. TypeScript uses a structural type system, so an empty type is a supertype of all types, and a generic type that doesn't use its type arguments will effectively not have type checking on those type parameters.
If Promise
used its type argument, you would see an error:
export class Promise<T> {
foo: T; // <- ADDED
}
export interface IId{
id:()=> string;
}
class Service {
get(id:string): Promise<IId> { return }
}
export interface IUser extends IId{
name: string
}
export interface IUserService{
test:(d:string) => Promise<IUser>;
}
class UserService implements IUserService{
constructor(private srv: Service){}
test(d:string):Promise<IUser> {
// ERROR
return this.srv.get("");
}
}
Trying to use C# (a nominal type system) as a reference point for TypeScript (a structural type system) isn't going to be very productive.
Upvotes: 2