如何在TypeScript中为对象动态分配属性?

时间:2012-10-03 14:42:54

标签: typescript

如果我想以编程方式将属性分配给Javascript中的对象,我会这样做:

var obj = {};
obj.prop = "value";

但在TypeScript中,这会产生错误:

  

属性'prop'在类型'{}'

的值上不存在

我应该如何在TypeScript中为对象分配任何新属性?

25 个答案:

答案 0 :(得分:253)

可以将obj表示为any,但这会破坏使用打字稿的整个目的。 obj = {}表示objObject。将其标记为any毫无意义。为了实现所需的一致性,可以如下定义接口。

interface LooseObject {
    [key: string]: any
}

var obj: LooseObject = {};

要使其紧凑:

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

LooseObject可以接受任意字符串作为键,any类型为值的字段。

obj.prop = "value";
obj.prop2 = 88;

此解决方案的真正优雅之处在于您可以在界面中包含类型安全字段。

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;

答案 1 :(得分:74)

或者一气呵成:

  var obj:any = {}
  obj.prop = 5;

答案 2 :(得分:50)

我倾向于将any放在另一边,即var 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; 

或者,您可以将这些属性标记为可选:

interface IFoo{
    bar?:string;
    baz?:string;
    boo?:string;    
}

// Now your simple initialization works
var foo:IFoo = {};

Try it online

答案 3 :(得分:36)

当您的对象具有特定类型时,此解决方案很有用。就像将对象获取到其他来源时一样。

let user: User = new User();
(user as any).otherProperty = 'hello';
//user did not lose its type here.

答案 4 :(得分:31)

虽然编译器抱怨它仍然应该根据需要输出它。但是,这将有效。

var s = {};
s['prop'] = true;

答案 5 :(得分:21)

另一个选择是将该属性作为集合访问:

&#13;
&#13;
var obj = {};
obj['prop'] = "value";
&#13;
&#13;
&#13;

答案 6 :(得分:5)

可以通过

将成员添加到现有对象
  1. 扩大类型(读取:扩展/专门化界面)
  2. 将原始对象强制转换为扩展类型
  3. 将成员添加到对象
  4. 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();
    

答案 7 :(得分:4)

将任何类型的对象存储在任何类型的对象上,将其类型化为“any”:

var extend = <any>myObject;
extend.NewProperty = anotherObject;

稍后您可以通过将扩展对象强制转换回'any'来检索它:

var extendedObject = <any>myObject;
var anotherObject = <AnotherObjectType>extendedObject.NewProperty;

答案 8 :(得分:4)

  • 情况1:

    var car = {type: "BMW", model: "i8", color: "white"}; car['owner'] = "ibrahim"; // You can add a property:

  • 情况2:

    var car:any = {type: "BMW", model: "i8", color: "white"}; car.owner = "ibrahim"; // You can set a property: use any type

答案 9 :(得分:4)

这里是Object.assign的特殊版本,它会在每次属性更改时自动调整变量类型。无需其他变量,类型断言,显式类型或对象副本:

function assign<T, U>(target: T, source: U): asserts target is T & U {
    Object.assign(target, source)
}

const obj = {};
assign(obj, { prop1: "foo" })
//  const obj now has type { prop1: string; }
obj.prop1 // string
assign(obj, { prop2: 42 })
//  const obj now has type { prop1: string; prop2: number; }
obj.prop2 // number

//  const obj: { prop1: "foo", prop2: 42 }

注意:sample使用TS 3.7 assertion functions。与assign不同,void的返回类型为Object.assign

答案 10 :(得分:4)

要确保该类型为Object(即键值对),请使用:

const obj: {[x: string]: any} = {}
obj.prop = 'cool beans'

答案 11 :(得分:3)

您可以使用传播运算符基于旧对象创建新对象

interface MyObject {
    prop1: string;
}

const myObj: MyObject = {
    prop1: 'foo',
}

const newObj = {
    ...myObj,
    prop2: 'bar',
}

console.log(newObj.prop2); // 'bar'

TypeScript会推断出原始对象的所有字段,而VSCode会进行自动补全,等等。

答案 12 :(得分:3)

Javascript:

myObj.myProperty = 1;

打字稿:

myObj['myProperty'] = 1;

答案 13 :(得分:3)

最佳做法是使用安全打字,我建议你:

interface customObject extends MyObject {
   newProp: string;
   newProp2: number;
}

答案 14 :(得分:3)

您可以添加此声明以使警告静音。

declare var obj: any;

答案 15 :(得分:2)

要保留以前的类型,请将对象临时转换为任何

  var obj = {}
  (<any>obj).prop = 5;

新的动态属性仅在您使用演员表时可用:

  var a = obj.prop; ==> Will generate a compiler error
  var b = (<any>obj).prop; ==> Will assign 5 to b with no error;

答案 16 :(得分:2)

我很惊讶没有答案引用Object.assign,因为当我想到JavaScript中的“组合”时,这就是我使用的技术。

它可以在TypeScript中按预期工作:

interface IExisting {
    userName: string
}

interface INewStuff {
    email: string
}

const existingObject: IExisting = {
    userName: "jsmith"
}

const objectWithAllProps: IExisting & INewStuff = Object.assign({}, existingObject, {
    email: "jsmith@someplace.com"
})

console.log(objectWithAllProps.email); // jsmith@someplace.com

优势

    始终
  • 输入安全性,因为您根本不需要使用any类型
  • 使用TypeScript的聚合类型(在声明&的类型时用objectWithAllProps表示),这清楚地表明我们正在动态(即动态地)构建新类型< / li>

注意事项

  1. Object.assign具有它自己的独特之处(对于大多数有经验的JS开发人员来说都是众所周知的),在编写TypeScript时应予以考虑。
    • 它可以以可变方式或不可变的方式使用(我在上面演示了不可变的方式,这意味着existingObject保持不变,因此没有email属性。对于大多数函数式程序员,这是一件好事,因为结果是唯一的新变化。
    • 当对象较扁平时,
    • Object.assign效果最佳。如果要合并两个包含可为空的属性的嵌套对象,最终可能会用undefined覆盖真实值。如果您注意Object.assign参数的顺序,那应该没问题。

答案 17 :(得分:1)

唯一具有类型安全性的解决方案是this one,但解决方案比较冗长,会迫使您创建多个对象。

如果您 必须 首先创建一个空对象,然后选择这两种解决方案之一。请记住,每次使用as都会失去安全性。

更安全的解决方案

objectgetObject的类型为安全,这意味着object.a的类型为string | undefined

interface Example {
  a: string;
  b: number;
}

function getObject() {
  const object: Partial<Example> = {};
  object.a = 'one';
  object.b = 1;
  return object as Example;
}

简短解决方案

objectgetObject的类型是不安全,这意味着object.a的类型将是string,即使在分配之前。 / p>

interface Example {
  a: string;
  b: number;
}

function getObject() {
  const object = {} as Example;
  object.a = 'one';
  object.b = 1;
  return object;
}

答案 18 :(得分:1)

尝试一下:

export interface QueryParams {
    page?: number,
    limit?: number,
    name?: string,
    sort?: string,
    direction?: string
}

然后使用它

const query = {
    name: 'abc'
}
query.page = 1

答案 19 :(得分:1)

如果您正在使用Typescript,可能您想要使用类型安全;在这种情况下裸体对象和任何&#39;是反对的。

最好不要使用Object或{},而是使用一些命名类型;或者您可能正在使用具有特定类型的API,您需要使用自己的字段进行扩展。我发现这个有用:

class Given { ... }  // API specified fields; or maybe it's just Object {}

interface PropAble extends Given {
    props?: string;  // you can cast any Given to this and set .props
    // '?' indicates that the field is optional
}
let g:Given = getTheGivenObject();
(g as PropAble).props = "value for my new field";

// to avoid constantly casting: 
let k:PropAble = getTheGivenObject();
k.props = "value for props";

答案 20 :(得分:1)

最简单的将是

const obj = <any>{};
obj.prop1 = "value";
obj.prop2 = "another value"

答案 21 :(得分:1)

在TypeScript中为对象动态分配属性。

要做到这一点你只需要使用这样的typescript接口:

interface IValue {
    prop1: string;
    prop2: string;
}

interface IType {
    [code: string]: IValue;
}

你可以像那样使用它

var obj: IType = {};
obj['code1'] = { 
    prop1: 'prop 1 value', 
    prop2: 'prop 2 value' 
};

答案 22 :(得分:0)

您可以使用:

this.model = Object.assign(this.model, { newProp: 0 });

答案 23 :(得分:0)

扩展Angular的@jmvtrinidad解决方案,

使用现有的类型化对象时,这是添加新属性的方法。

let user: User = new User();
(user as any).otherProperty = 'hello';
//user did not lose its type here.

现在,如果您想在HTML端使用otherProperty,这就是您需要的:

<div *ngIf="$any(user).otherProperty">
   ...
   ...
</div>

当使用$any()any强制转换时,Angular编译器将<any>视作对as any类型的强制转换。

答案 24 :(得分:-2)

如果您能够使用ES6 JavaScript功能,则可以使用Computed Property Names轻松处理此问题:

var req = {id : 0123456};    
var response = {responses: {[req.id]: 'The 0123456 response message'}};

[req.id]对象键具有动态值