我在 TypeScript 中有一些动态生成的函数名称。我现在可以使用它们的唯一方法是将我的对象转换为 <any>
.例如:<any>myInstance.getDataA()
.这些函数是根据一些规则动态生成的。基于相同的规则,我想为我的 class
生成类型定义。 es,但我无法让它工作。
原始.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';
}
}
我的类.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'
我想自动生成一个定义文件来定义这些动态属性。
例如:
我的类.def.ts
declare interface MyClass {
getDataA;
setDataA
}
//my-other-class.def.ts
declare interface MyClass {
getDataB;
setDataB
}
但我无法为我的定义文件找到使其工作的语法。有什么不明白的请问我,有什么想法请帮忙!
最佳答案
为 4.1 编辑
使用 Template literal types and mapped type 'as' clauses我们现在可以在类型系统中连接字符串并创建一个动态创建这些属性的类。
function defineDynamicClass<T extends string[]>(...info: T): {
new (): {
[K in T[number] as `get${Capitalize<K>}`]: () => unknown
} & {
[K in T[number] as `set${Capitalize<K>}`]: (value: unknown) => void
} & {
info: T
}
} {
return class {
get info () {
return info;
}
} as any
}
class MyClass extends defineDynamicClass('A', 'B', 'ABAB') {
}
let s =new MyClass();
s.getA();
s.getABAB();
s.setA("")
s.info;
4.1 之前
语言内方法
在类型系统中没有办法做到这一点,因为我们不能对字符串文字类型执行字符串操作。在没有外部工具的情况下,您可以获得的最接近的方法是创建采用字符串文字类型的 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%,但根据我们之前的讨论,目标是为方法提供完整的代码完成,而这种方法实现了这一点。如果您传入错误的值并获得字符串的完成列表,则会出现错误:
编译器 API 方法
第二种方法是创建一个使用 typescript compiler API 的自定义工具解析 ts 文件,查找派生自 Original
的类并生成包含方法的接口(interface)(在同一文件或不同文件中),如果您对此感兴趣,我可以编写代码,但是这不是微不足道的,虽然编译器 API 是稳定的,但我认为编译器团队对向后兼容性的关注程度不如他们对语言的关注程度(事实上,这是他们在文档页面中所做的确切声明)。
如果您对这样的解决方案感兴趣,请告诉我,我可以提供,但我建议您不要这样做。
关于javascript - TypeScript:自动生成的动态函数名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51026068/