我想在不知道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
}
答案 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
}
}