我在TypeScript中有一些动态生成的函数名。我现在可以使用它们的唯一方法是将对象投射到<any>
。例如:<any>myInstance.getDataA()
。这些功能是根据某些规则动态生成的。基于相同的规则,我想为我的class
生成类型定义,但是我无法使其工作。
original.ts
abstract class Original {
dynamics = ['getData', 'setData'];
constructor() {
// I create functions here dynamically
this.dynamics.forEach((key) => {
this[key + this.info] = () => null;
});
}
get info() {
return 'X';
}
}
my-class.ts
class MyClass extends Original {
get info() {
return 'A';
}
}
我的其他班级.ts
class MyOtherClass extends Original {
get info() {
return 'B';
}
}
something.ts
const myInstance = new MyClass();
console.log(myInstance.getDataA()); // TS2339: Property getDataA does not exist on type: 'MyClass'
const myOtherInstance = new MyOtherClass();
console.log(myInstance.getDataB()); // TS2339: Property getDataB does not exist on type: 'MyClass'
我想自动生成一个定义文件来定义这些动态属性。
例如:
my-class.def.ts
declare interface MyClass {
getDataA;
setDataA
}
//my-other-class.def.ts
declare interface MyClass {
getDataB;
setDataB
}
但是我找不到我的定义文件使用的语法。请问我是否不清楚,请帮助您!
答案 0 :(得分:5)
在类型系统内无法执行此操作,因为我们无法对字符串文字类型执行字符串操作。在没有外部工具的情况下,最接近的方法是创建带有字符串文字类型的get/set
方法,该方法与getInfo
方法返回的字符串相同。
function stringLiteralArray<T extends string>(...v: T[]){ return v;}
abstract class Original {
get(name: this['info'][number]) {
return null;
}
set(name: this['info'][number], value: any) {
return null;
}
get info() : string[]{
return [];
}
}
class MyOtherClass extends Original {
get info() {
return stringLiteralArray('A', 'B', 'ABAB');
}
}
class MyClass extends Original {
get info() {
return stringLiteralArray('C', 'D', 'DEDE');
}
}
let s =new MyClass();
s.get('A') // error
s.get('C') // ok
虽然这种方法不是您想要的100%,但在我们之前的讨论中,目的是为这些方法提供完整的代码完成,并且这种方法可以实现这一目标。如果您输入错误的值,则会得到错误,并且您会得到字符串的完成列表:
第二种方法是创建一个自定义工具,该工具使用打字稿compiler API来解析ts文件,查找从Original
派生的类并生成包含方法的接口(可以在同一文件中或其他文件),如果您对此感兴趣,我可以编写代码,但它并不简单,尽管编译器API稳定,但我认为编译器团队在处理向后兼容性方面不如使用语言(实际上,这是他们在文档页面中做出的确切声明)。
如果您对这样的解决方案感兴趣,请告诉我,我可以提供,但我建议不要这样做。