我正在尝试为我的项目生成 d.ts
声明文件。
有两个类确实计算繁重的逻辑,其余的类继承自它们。子类的属性不是在对象本身上定义的,而是在类内名为 defaults
的 getter
上定义的,并在运行时定义。
基础模型
abstract class BaseModel {}
abstract class Model extends BaseModel {}
继承模型
class Example extends Model {
get defaults() {
return {
someProp: 1,
anotherProp: 2
}
}
}
我的代码运行良好,但动态添加的属性没有自动完成。我尝试将以下内容添加到 d.ts 文件以使其了解动态属性,但它似乎不起作用。
index.d.ts
class Model<T> extends BaseModel {
[P in keyof T]: T[P]
}
type ExampleType = {
someProp : number
anotherProp : number
}
class Example extends Model<ExampleType> {}
如何向继承的类添加属性定义,而无需手动定义它们?
最佳答案
您不能直接执行此操作,如果您使用额外的函数创建类,则可以执行此操作,该函数会改变创建类以添加属性:
type ReplaceInstanceType<T extends new (...args: any[])=> any, TNewInstance> =
T extends new (...args: infer U)=> any ?
new (...args: U) => TNewInstance :
never;
function createModel<T extends new (...args: any[])=> any>(modelClass: T) :
ReplaceInstanceType<T, InstanceType<T> & InstanceType<T>['defaults']> {
return modelClass as any;
}
注意这使用了 3.0 功能 Tuples in rest parameters and spread expressions
对于 ReplaceInstanceType
的 2.9、2.8 版本,请参阅 this answer
我们可以通过以下两种方式之一使用它:
直接使用createModel
的输出:
const Example = createModel(class extends Model {
constructor (data: string) {
super();
// this.anotherProp // Not ok we can't access teh extra fields inside the class
}
get defaults() {
return {
someProp: 1,
anotherProp: 2
}
}
});
new Example(``).anotherProp // we can create the class and access the extra fields
new Example("").someProp
这样做的缺点是额外的字段不能从类本身内部使用,这在某些情况下可能是一个问题。
第二种用法是在新类的extends子句中使用createModel
,并且只在我们传递给extends的类中定义默认值,在外部类中添加额外的方法:
class Example extends createModel(class extends Model {
get defaults() {
return {
someProp: 1,
anotherProp: 2
}
}
}) {
constructor(data: string) {
super();
this.anotherProp // new properties are accesible
}
};
new Example(``).anotherProp // we can create the class and access the extra fields
new Example("").someProp
此方法的缺点是实际上创建了 2 个类,我们实际使用的外部类和我们用来添加默认属性的内部类。
编辑
由于 typescript 实际上在强类型和验证键名称方面做得非常好,您也可以考虑使用 get/set
方法来代替,您可以获得良好的代码完成和类型验证,但它有点多详细:
abstract class BaseModel {
abstract get defaults();
get<K extends keyof this['defaults']>(name: keyof this['defaults']): this['defaults'][K]{
return this[name] as any;
}
set<K extends keyof this['defaults']>(name: keyof this['defaults'], value: this['defaults'][K]) : void{
this[name] = value;
}
}
class Example extends BaseModel {
get defaults() {
return {
someProp: 1,
anotherProp: 2
}
}
};
new Example().get('anotherProp')
new Example().get("someProp")
new Example().set("someProp", 1) //
new Example().set("someProp", "1") // error wrong type
new Example().get("someProp2") // error
关于typescript - 定义从继承类动态生成的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51514486/