bsr
bsr

Reputation: 58732

static typting and generic contravariance

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

Answers (1)

Ryan Cavanaugh
Ryan Cavanaugh

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

Related Questions