打字稿通过引用传递属性

时间:2019-10-02 20:56:08

标签: typescript pass-by-reference pass-by-name

我有一个具有4个不同属性的Typescript类,如下所示:

class MyClass {
     private x: number;
     private y: number;
     private z: number;
     private w: number;
}

我想创建四个增加这些属性的函数:

   incrementX() { this.x++; }
   incrementY() { this.y++; )
   ...

但是,我不想复制增量逻辑(++),而是要将其放在一个函数中。如果Typescript具有ref参数(例如C#),我将执行以下操作:

   incrementX() { this.increment(ref this.x); }
   increment(p: ref number) { p++; }

Typescript不支持通过引用传递。实现此操作的非类型安全方式是:

   incrementX() { this.increment("x"); }
   increment(p: string) {
       const self = this as any;
       self[p]++;
   }

这不是类型安全的。我可以轻松地调用increment('not-a-property'),而不会从编译器中收到错误。我添加了运行时检查,以确保self [p]确实是一个数字,但我仍然希望编译器可以捕获某些内容。

是否有实现此目的的类型安全方式?

注意:很明显,我的实际代码并没有增加数字,而是做了一些相当复杂的事情-不是关于数字,而是关于另一个类类型。

2 个答案:

答案 0 :(得分:1)

您可以使用keyofnumber extends吗?只允许传递类的数字键。

Playground here

class MyClass {
  public a: number = 0;
  public b: number = 0;
  public c: string = "";

  public increment(
     key: {
      [K in keyof MyClass]-?: number extends MyClass[K] ? K : never
    }[keyof MyClass]
  ) {
    this[key]++;
  }
}

const test = new MyClass();

test.increment("a");
test.increment("b");
test.increment("c"); // fail
test.increment("d"); // fail

答案 1 :(得分:1)

一种解决方案是使用keyof MyClass键入p。

     increment(p: keyof MyClass): void {
       this[p]++;
     }

但是它行不通。因为您的数字字段是private,并且因为在MyClass的键中,所以您本身具有函数increment

一种解决方案是仅提取数字字段:

type OnlyNumberKeys<O> = {
  [K in keyof O]: O[K] extends number ? K : never;
}[keyof O];

然后在increment函数中使用此类型:

class MyClass {
     x: number;
     y: number;
     z: number;
     w: number;

     increment(p: OnlyNumberKeys<MyClass>): void {
       this[p]++;
     }
}

现在p仅接受'x' | 'y' | 'z' | 'x'

请注意,我必须删除所有private关键字。我不知道是否有解决方案。