Mat*_*ams 1 generics traits mixins typescript typescript-generics
我正在使用带有子类工厂模式的 TypeScript 的 mixins/traits,如https://mariusschulz.com/blog/mixin-classes-in-typescript 所述。有问题的特征被称为Identifiable,它将一个id属性赋予一个应该表达Identifiable特征的类。当我尝试以Nameable特定顺序将 trait 与另一个非通用 trait ( ) 一起使用时,编译失败。
class Empty {}
type ctor<T = Empty> = new(...args: any[]) => T;
function Nameable<T extends ctor = ctor<Empty>>(superclass: T = Empty as T) {
return class extends superclass {
public name?: string;
};
}
function Identifiable<ID, T extends ctor = ctor<Empty>>(superclass: T = Empty as T) {
return class extends superclass {
public id?: ID;
};
}
class Person1 extends Nameable(Identifiable<string>()) { // compiles
constructor(name?: string) {
super();
this.name = name;
this.id = "none";
}
}
class Person2 extends Identifiable<string>(Nameable()) { // fails to compile
constructor(name?: string) {
super();
this.name = name;
this.id = "none";
}
}
Run Code Online (Sandbox Code Playgroud)
编译错误是
src/test/unit/single.ts:30:10 - error TS2339: Property 'name' does not exist on type 'Person2'.
30 this.name = name;
~~~~
Run Code Online (Sandbox Code Playgroud)
如何让通用特征正确编译,而不管它们的使用顺序如何?
注意:此问题的公共 git 存储库位于https://github.com/matthewadams/typetrait。如果你想玩这个,一定要检查minimal分支。
这个问题其实很简单,和typescript没有部分类型参数推断有关。调用Identifiable<string>(...)并不意味着您设置ID并让编译器推断T. 它实际上意味着 use stringforID和使用默认值(即Empty) for T。这是不幸的,并且有一个允许部分推理的提议,但它没有获得太多的关注。
您有两种选择,要么使用函数柯里化来执行两次调用方法,其中第一个调用通过ID,第二个调用推断T:
class Empty { }
type ctor<T = Empty> = new (...args: any[]) => T;
function Nameable<T extends ctor = ctor<Empty>>(superclass: T = Empty as T) {
return class extends superclass {
public name?: string;
};
}
function Identifiable<ID>() {
return function <T extends ctor = ctor<Empty>>(superclass: T = Empty as T) {
return class extends superclass {
public id?: ID;
};
}
}
class Person2 extends Identifiable<string>()(Nameable()) {
constructor(name?: string) {
super();
this.name = name;
this.id = "none";
}
}
Run Code Online (Sandbox Code Playgroud)
或者ID通过使用虚拟参数作为推理站点来使用推理:
class Empty { }
type ctor<T = Empty> = new (...args: any[]) => T;
function Nameable<T extends ctor = ctor<Empty>>(superclass: T = Empty as T) {
return class extends superclass {
public name?: string;
};
}
function Identifiable<ID, T extends ctor = ctor<Empty>>(type: ID, superclass: T = Empty as T) {
return class extends superclass {
public id?: ID;
};
}
}
class Person2 extends Identifiable(null! as string, Nameable()) {
constructor(name?: string) {
super();
this.name = name;
this.id = "none";
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
479 次 |
| 最近记录: |