【问题标题】:Typescript dynamic class methods打字稿动态类方法
【发布时间】:2015-07-08 21:22:39
【问题描述】:

问题

如何将类型检查添加到动态创建的类方法中?

示例

给定一个非常简单的Property 类。

class Property {
  value: any;
  name: string;

  constructor(name: string, value: any) {
    this.name = name;
    this.value = value
  }
}

还有一个Entity

class Entity {
  name: string;
  properties: Property[];


  constructor(name: string, properties: Property[]) {
    this.name = name;
    this.properties = properties;

    this.properties.forEach((p: Property, index: number) => {
      this[p.name] = (value: string): any => {
        if (value) {
          this.properties[index].value = value;
        }
        return this.properties[index].value;
      }
    }, this);
  }
}

重要部分:this[p.name] = function ...(我们不知道“transpile”时方法的名称)。

我们在转成 javascript 时遇到如下错误:

var car = new domain.Entity(
  'car',
  [
    new domain.Property('manufacturer', 'Ford'),
    new domain.Property('model', 'Focus')
  ]
);

car.model() // error TS2339: Property 'model' does not exist on type 'Entity'.

我知道这是类的不常见用法,因为Entity 的不同实例将定义不同的方法。有没有办法消除错误,即 typescript 能够识别每个实例的正确界面,或者至少 消除错误

注意事项

这是有效的 javascript,可以通过以下方式使用它:

var car = new domain.Entity(
  'car',
  [
    new domain.Property('manufacturer', 'Ford'),
    new domain.Property('model', 'Focus')
  ]
);

car.model()          // 'Focus'
car.model('Transit') // 'Transit'

我知道这是在 similar question 上提出的,但这种情况略有不同,因为方法名称也是在运行时定义的。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    如果您有想要访问的动态属性,请使用 any 类型绕过变量的类型检查。您可以从一开始就使用 any 类型声明变量,或者稍后使用类型断言运算符 (as)。所以这里有一些可能的变体:

    var car: any = new domain.Entity(...);
    car.model();
    
    var car = new domain.Entity(...) as any;
    car.model();
    
    var car = new domain.Entity(...);
    (car as any).model();
    

    【讨论】:

    • 感谢 Vadim,这解决了编译错误。我不知道as 运算符,它非常好用。
    【解决方案2】:

    添加这种类型(只需要一次):

    interface Prop<T> {
        (): T;
        (value: T): T;
    }
    

    然后你可以为你创建的每个形状写这个:

    interface Car extends Entity {
        model: Prop<string>;
        manufacturer: Prop<string>;
    }
    let car = <Car>new Entity('car', [/*...*/]);
    car.model(32); // Error
    let x = car.model(); // x: string
    

    【讨论】:

    • 我也许应该将这个添加到问题中,但我的目标是能够创建新的 Entity 实例(具有不同的属性)而无需更改任何代码(例如从 JSON 文件)。因此,不幸的是,这将不起作用。如果有人感兴趣,这称为自适应对象模型adaptiveobjectmodel.com/WICSA3/ArchitectureOfAOMsWICSA3.pdf
    • 我以前从未见过这种语法。文档链接?
    猜你喜欢
    • 2019-11-10
    • 2023-02-10
    • 2020-05-21
    • 1970-01-01
    • 2022-11-25
    • 2021-09-10
    • 2020-04-02
    • 2020-03-09
    • 2022-12-19
    相关资源
    最近更新 更多