在TypeScript中声明动态添加的类属性

时间:2016-12-08 11:50:11

标签: class typescript properties typescript-typings tsc

我想在不知道TypeScript中属性名称,值和值类型的情况下将属性分配给类的实例。让我们假设我们有以下example.ts脚本:

// This could be a server response and could look totally diffent another time...
const someJson:string = '{ "foo": "bar", "bar": "baz" }'

class MyClass {
  someProperty:boolean

  constructor( json:string ) {
    const parsedJson:any = JSON.parse( json )

    Object.keys( parsedJson ).forEach(
      ( key:string ) => {
        this[ key ] = parsedJson[ key ]
      }
    )

    this['someProperty'] = true
  }
}

const myInstance = new MyClass( someJson )

// Works fine, logs `true`.
console.log( myInstance.someProperty )

// Error: Property 'foo' does not exist on type 'MyClass'.
console.log( myInstance.foo )

// Error: Property 'bar' does not exist on type 'MyClass'.
console.log( myInstance.bar )

如何确保TypeScript编译器不会抱怨动态添加的属性,而是将它们作为任意类型的"key": value对处理。我仍然希望tsc确保myInstance.someProperty必须是boolean类型但是我希望能够获得myInstance.whatever,即使它未定义而没有运行到编译器中错误。

我没有找到任何证明这一点的文件。也许是因为我不是母语为英语的人。所以请保持简单的答案。

修改

我记得有类似下面的内容,但我从来没有这样做过:

interface IMyClass {
  [name:string]: any
}

2 个答案:

答案 0 :(得分:7)

问题是你在运行时添加新属性,编译器无法知道。

如果您事先知道了属性名称,那么您可以这样做:

type Json = {
    foo: string;
    bar: string;
}

...

const myInstance = new MyClass(someJson) as MyClass & Json;
console.log(myInstance.foo) // no error

修改

如果您事先不知道这些属性,则无法执行此操作:

console.log(myInstance.foo);

因为那时你知道foo是收到的json的一部分,你可能会有类似的东西:

let key = getKeySomehow();
console.log(myInstance[key]);

这应该没有编译器的错误,唯一的问题是编译器不知道返回值的类型,它将是any

所以你可以这样做:

const myInstance = new MyClass(someJson) as MyClass & { [key: string]: string };
let foo = myInstance["foo"]; // type of foo is string
let someProperty = myInstance["someProperty"]; // type of someProperty is boolean

第二次编辑

你知道道具,但不在课堂上,你可以这样做:

type ExtendedProperties<T> = { [P in keyof T]: T[P] };
function MyClassFactory<T>(json: string): MyClass & ExtendedProperties<T> {
    return new MyClass(json) as MyClass & ExtendedProperties<T>;
}

然后你就这样使用它:

type Json = {
    foo: string;
    bar: string;
};
const myInstance = MyClassFactory<Json>(someJson);

请注意,这仅适用于打字稿2.1及更高版本。

答案 1 :(得分:2)

您可以将 index signature 添加到您的班级:

class MyClass {
  [index: string]: any; //index signature

  someProperty:boolean

  constructor( json:string ) {
    const parsedJson:any = JSON.parse( json )

    Object.keys( parsedJson ).forEach(
      ( key:string ) => {
        this[ key ] = parsedJson[ key ]
      }
    )

    this['someProperty'] = true
  }
}