如何在 TypeScript 中为对象动态分配属性?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12710905/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I dynamically assign properties to an object in TypeScript?
提问by Peter Olson
If I wanted to programatically assign a property to an object in Javascript, I would do it like this:
如果我想以编程方式为 Javascript 中的对象分配一个属性,我会这样做:
var obj = {};
obj.prop = "value";
But in TypeScript, this generates an error:
但是在 TypeScript 中,这会产生一个错误:
The property 'prop' does not exist on value of type '{}'
“{}”类型的值上不存在属性“prop”
How am I supposed to assign any new property to an object in TypeScript?
我应该如何为 TypeScript 中的对象分配任何新属性?
回答by Akash Kurian Jose
It is possible to denote obj
as any
, but that defeats the whole purpose of using typescript. obj = {}
implies obj
is an Object
. Marking it as any
makes no sense. To accomplish the desired consistency an interface could be defined as follows.
可以表示obj
为any
,但这违背了使用打字稿的全部目的。obj = {}
暗示obj
是一个Object
. 将其标记为any
没有意义。为了实现所需的一致性,可以如下定义接口。
interface LooseObject {
[key: string]: any
}
var obj: LooseObject = {};
OR to make it compact:
或使其紧凑:
var obj: {[k: string]: any} = {};
LooseObject
can accept fields with any string as key and any
type as value.
LooseObject
可以接受任何字符串作为键和any
类型作为值的字段。
obj.prop = "value";
obj.prop2 = 88;
The real elegance of this solution is that you can include typesafe fields in the interface.
此解决方案的真正优雅之处在于您可以在界面中包含类型安全字段。
interface MyType {
typesafeProp1?: number,
requiredProp1: string,
[key: string]: any
}
var obj: MyType ;
obj = { requiredProp1: "foo"}; // valid
obj = {} // error. 'requiredProp1' is missing
obj.typesafeProp1 = "bar" // error. typesafeProp1 should be a number
obj.prop = "value";
obj.prop2 = 88;
While this answers the Original question, the answer hereby @GreeneCreations might give another perspective at how to approach the problem.
虽然这回答了原来的问题,答案在这里通过@GreeneCreations可能会给如何来解决这个问题另一个角度。
回答by Crwth
Or all in one go:
或者一次性完成:
var obj:any = {}
obj.prop = 5;
回答by basarat
I tend to put any
on the other side i.e. var foo:IFoo = <any>{};
So something like this is still typesafe:
我倾向于放在any
另一边 ievar foo:IFoo = <any>{};
所以这样的事情仍然是类型安全的:
interface IFoo{
bar:string;
baz:string;
boo:string;
}
// How I tend to intialize
var foo:IFoo = <any>{};
foo.bar = "asdf";
foo.baz = "boo";
foo.boo = "boo";
// the following is an error,
// so you haven't lost type safety
foo.bar = 123;
Alternatively you can mark these properties as optional:
或者,您可以将这些属性标记为可选:
interface IFoo{
bar?:string;
baz?:string;
boo?:string;
}
// Now your simple initialization works
var foo:IFoo = {};
回答by jmvtrinidad
This solution is useful when your object has Specific Type. Like when obtaining the object to other source.
当您的对象具有特定类型时,此解决方案很有用。就像将对象获取到其他来源时一样。
let user: User = new User();
(user as any).otherProperty = 'hello';
//user did not lose its type here.
回答by Angelo R.
Although the compiler complains it should still output it as you require. However, this will work.
尽管编译器抱怨它仍然应该根据您的需要输出它。但是,这将起作用。
var s = {};
s['prop'] = true;
回答by Aviw
One more option do to that is to access the property as a collection:
另一种选择是将属性作为集合访问:
var obj = {};
obj['prop'] = "value";
回答by GreeneCreations
I'm surprised that none of the answers reference Object.assign since that's the technique I use whenever I think about "composition" in JavaScript.
我很惊讶没有一个答案引用 Object.assign,因为这是我在考虑 JavaScript 中的“组合”时使用的技术。
And it works as expected in TypeScript:
它在 TypeScript 中按预期工作:
interface IExisting {
userName: string
}
interface INewStuff {
email: string
}
const existingObject: IExisting = {
userName: "jsmith"
}
const objectWithAllProps: IExisting & INewStuff = Object.assign({}, existingObject, {
email: "[email protected]"
})
console.log(objectWithAllProps.email); // [email protected]
Advantages
好处
- type safety throughout because you don't need to use the
any
type at all - uses TypeScript's aggregate type (as denoted by the
&
when declaring the type ofobjectWithAllProps
), which clearly communicates that we're composing a new type on-the-fly (i.e. dynamically)
- 类型安全,因为你根本不需要使用
any
类型 - 使用 TypeScript 的聚合类型(由
&
声明类型时的表示objectWithAllProps
),它清楚地表明我们正在即时(即动态地)组合一个新类型
Things to be aware of
需要注意的事项
- Object.assign has it's own unique aspects (that are well known to most experienced JS devs) that should be considered when writing TypeScript.
- It can be used in a mutable fashion, or an immutable manner (I demonstrate the immutable way above, which means that
existingObject
stays untouched and therefore doesn't have anemail
property. For most functional-style programmers, that's a good thing since the result is the only new change). - Object.assign works the best when you have flatter objects. If you are combining two nested objects that contain nullable properties, you can end up overwriting truthy values with undefined. If you watch out for the order of the Object.assign arguments, you should be fine.
- It can be used in a mutable fashion, or an immutable manner (I demonstrate the immutable way above, which means that
- Object.assign 有自己独特的方面(大多数有经验的 JS 开发人员都知道),在编写 TypeScript 时应该考虑这些方面。
- 它可以以可变方式或不可变方式使用(我在上面演示了不可变方式,这意味着
existingObject
保持不变,因此没有email
属性。对于大多数函数式程序员来说,这是一件好事,因为结果是唯一的新变化)。 - Object.assign 在您拥有更扁平的对象时效果最佳。如果要组合包含可为空属性的两个嵌套对象,则最终可能会用 undefined 覆盖真值。如果你注意 Object.assign 参数的顺序,你应该没问题。
- 它可以以可变方式或不可变方式使用(我在上面演示了不可变方式,这意味着
回答by Alex
You can create new object based on the old object using the spread operator
您可以使用扩展运算符基于旧对象创建新对象
interface MyObject {
prop1: string;
}
const myObj: MyObject = {
prop1: 'foo',
}
const newObj = {
...myObj,
prop2: 'bar',
}
console.log(newObj.prop2); // 'bar'
TypeScript will infer all the fields of the original object and VSCode will do autocompletion, etc.
TypeScript 会推断原始对象的所有字段,VSCode 会自动完成等。
回答by Jayant Varshney
Simplest will be following
最简单的将跟随
const obj = <any>{};
obj.prop1 = "value";
obj.prop2 = "another value"
回答by Daniel Dietrich
It is possible to add a member to an existing object by
可以通过以下方式向现有对象添加成员
- widening the type (read: extend/specialize the interface)
- cast the original object to the extended type
- add the member to the object
- 扩展类型(阅读:扩展/专门化接口)
- 将原始对象强制转换为扩展类型
- 将成员添加到对象
interface IEnhancedPromise<T> extends Promise<T> {
sayHello(): void;
}
const p = Promise.resolve("Peter");
const enhancedPromise = p as IEnhancedPromise<string>;
enhancedPromise.sayHello = () => enhancedPromise.then(value => console.info("Hello " + value));
// eventually prints "Hello Peter"
enhancedPromise.sayHello();