静态打字和通用逆转

时间:2014-03-13 11:51:51

标签: generics typescript

请参阅代码here它是打字稿,但由于与C#的相似性,它也适用于它。

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("");
    }
}

说,我有一个框架服务函数get,它返回类型IId的承诺。在我的自定义类中,我有一个方法,它被定义为返回类型为IUser的promise。我返回this.srv.get("")并返回Promise<IId>时犯了一个错误。但这不应与Promise<IUser>兼容,因为IUser期待name字段。为什么没有错误?

我不熟悉C#泛型,这就是所谓的contravariance。阅读一些文章,但无法绕过它。

1 个答案:

答案 0 :(得分:2)

您的Promise类型为空不使用T,这两个都是非常大的问题。 TypeScript使用结构类型系统,因此空类型是所有类型的超类型,并且不使用其类型参数的泛型类型实际上不会对这些类型参数进行类型检查。

如果Promise使用了其类型参数,您会看到错误:

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("");
    }
}

尝试使用C#(名义类型系统)作为TypeScript(结构类型系统)的参考点并不会非常高效。