如何在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-11 00:48:37  来源:igfitidea点击:

How do I dynamically assign properties to an object in TypeScript?

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 objas any, but that defeats the whole purpose of using typescript. obj = {}implies objis an Object. Marking it as anymakes no sense. To accomplish the desired consistency an interface could be defined as follows.

可以表示objany,但这违背了使用打字稿的全部目的。obj = {}暗示obj是一个Object. 将其标记为any没有意义。为了实现所需的一致性,可以如下定义接口。

interface LooseObject {
    [key: string]: any
}

var obj: LooseObject = {};

OR to make it compact:

或使其紧凑:

var obj: {[k: string]: any} = {};

LooseObjectcan accept fields with any string as key and anytype 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 anyon 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 = {};

Try it online

网上试试

回答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 anytype at all
  • uses TypeScript's aggregate type (as denoted by the &when declaring the type of objectWithAllProps), which clearly communicates that we're composing a new type on-the-fly (i.e. dynamically)
  • 类型安全,因为你根本不需要使用any类型
  • 使用 TypeScript 的聚合类型(由&声明类型时的表示objectWithAllProps),它清楚地表明我们正在即时(即动态地)组合一个新类型

Things to be aware of

需要注意的事项

  1. 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 existingObjectstays untouched and therefore doesn't have an emailproperty. 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.
  1. 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

可以通过以下方式向现有对象添加成员

  1. widening the type (read: extend/specialize the interface)
  2. cast the original object to the extended type
  3. add the member to the object
  1. 扩展类型(阅读:扩展/专门化接口)
  2. 将原始对象强制转换为扩展类型
  3. 将成员添加到对象
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();