打字稿中的类和关键字

时间:2019-01-15 21:34:43

标签: typescript

从TypeScript开始,我尝试使用keyof在类上定义动态属性:

type UserType = {
  id: number,
  name: string,
}

class Domain<T> {
  _data: T;
  [K in keyof T]: T[K]; // Does not build:
                        // (1) A computed property name must be of type 
                        //     'string', 'number', 'symbol', or 'any'
                        // (2) Cannot find name 'keyof'


  constructor(data: T) {
    this._data = data;
    Object.keys(data).forEach((key) => Object.defineProperty(this, key, { get: () => this._data[key] }));
  }
}

const joeData: UserType = {
  id: 1,
  name: 'Joe',
}

const joe = new Domain(joeData); // type: Domain<UserType>
console.log(joe.id);

我确实使用与()相同的语法编写了这段代码:

type Foo<T> = {
  [K in keyof T]: T[K];
}

有关如何解决此问题的任何提示?

2 个答案:

答案 0 :(得分:3)

映射的类型不能在接口或类中使用。它们只能在类型别名中使用。

如果涉及泛型,则接口和类继承不能与映射类型很好地混合。 Typescript希望预先知道基类/接口的形状,因此我们可以编写如下内容:

interface Foo extends Pick<UserType, keyof UserType> {

}

我们不能写

interface Foo<T> extends Pick<T, keyof T> { //An interface can only extend an object type or intersection of object types with statically known members

}

这消除了使用类接口合并欺骗编译器的任何可能性。

唯一的解决方法是分别定义类,并使用自定义构造函数签名。定制构造函数签名可以具有通用类型参数,并且可以在返回的实例类型中使用它。我们可以将返回的类型设为Domain类的实例,与T相交:

type UserType = {
    id: number,
    name: string,
}

class _Domain<T>  {
    _data: T;
    constructor(data: T) {
        this._data = data;
        Object.keys(data).forEach((key) => Object.defineProperty(this, key, { get: () => this._data[key] }));
    }
}

const Domain = _Domain as ({
    new <T>(data: T): _Domain<T> & T
})

const joeData: UserType = {
    id: 1,
    name: 'Joe',
}

const joe = new Domain(joeData); // type: _Domain<UserType> & UserType
console.log(joe.id);

答案 1 :(得分:0)

我认为现在有办法动态指定这样的类属性。它也不能在interface中使用。我用implements Foo<T>尝试了您的班级变体,并收到以下错误消息:

  

类只能实现对象类型或具有静态已知成员的对象类型的交集。

这使我相信Typescript是专门为避免动态指定的类属性而设计的。

您可以使用非类的构造函数来执行此操作。您可以将Foo类型用作使用getter构造普通对象的函数的返回类型。或者,如果您只需要对象的只读版本,则可以使用Object.freeze(data)