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

Pet*_*son 291 typescript

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

var obj = {};
obj.prop = "value";
Run Code Online (Sandbox Code Playgroud)

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

类型"{}"的值不存在属性"prop"

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

Aka*_*ose 341

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

interface LooseObject {
    [key: string]: any
}

var obj: LooseObject = {};
Run Code Online (Sandbox Code Playgroud)

或者使其紧凑:

var obj: {[k: string]: any} = {};
Run Code Online (Sandbox Code Playgroud)

LooseObject可以接受任何字符串作为键并any键入值的字段.

obj.prop = "value";
obj.prop2 = 88;
Run Code Online (Sandbox Code Playgroud)

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

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;
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是现在最好的解决方案.我认为当时问题被问到这样的索引属性还没有在TypeScript中实现. (12认同)
  • 现在,您可以编写“Record<string,any>”,而不是“{[key: string]:any}” (3认同)
  • 现在建议使用 `Record<string,unknown>` 以避免使用 `any` 类型 (3认同)

Crw*_*wth 77

或者一气呵成:

  var obj:any = {}
  obj.prop = 5;
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案删除类型信息 (58认同)
  • 如果为了使用它,我必须为"any"投射这么多东西,那么TypeScript有什么意义呢?只是在我的代码中变成了额外的噪音..:/ (32认同)
  • @AjaxLeung如果你需要这样做,你就错了. (10认同)
  • @AjaxLeung您应该很少将其转换为`any`。TypeScript用于在编译时捕获(潜在)错误。如果您强制转换为“ any”以使错误静音,那么您将失去键入的能力,并可能会返回纯JS。理想情况下,仅在导入无法编写TS定义的代码或将代码从JS迁移到TS时使用“ any” (5认同)
  • 请参见上面的其他保留对象先前类型的编辑。 (2认同)
  • @M.Arjmandi - 事实并非如此。问题是问你应该如何用打字稿来处理这个问题。Typescript 的全部要点是避免 javascript 动态的烦人的一面 - javascript 中的所有内容都有效地转换为任何默认值。客观来说这不是一个好的答案。 (2认同)

bas*_*rat 57

我倾向于放在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; 
Run Code Online (Sandbox Code Playgroud)

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

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

// Now your simple initialization works
var foo:IFoo = {};
Run Code Online (Sandbox Code Playgroud)

在线尝试

  • +1是保持类型安全的唯一解决方案.只需确保在其后直接实例化所有非可选属性,以避免以后出现错误. (5认同)
  • `我还有<any> {`那么你还没有编译.TypeScript会在其发射中删除它 (4认同)
  • 如今,首选var foo:IFoo = {}。类型转换的旧语法与TSX(Typescript定义的JSX)相冲突。 (2认同)

jmv*_*dad 40

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

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

  • 这是一次性作业的正确解决方案. (6认同)
  • 这个答案对我有用,因为对于 facebook 登录,我必须向 **window** 对象添加属性。我第一次在 TypeScript 中使用 **as** 关键字。 (2认同)

Ang*_* R. 34

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

var s = {};
s['prop'] = true;
Run Code Online (Sandbox Code Playgroud)

  • 不要使用 var.. 而是使用 let 或 const (4认同)
  • 是的,这不是真正的类型脚本方式,你失去了智能感知。 (3认同)

Gre*_*ons 25

我很惊讶没有一个答案引用 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
Run Code Online (Sandbox Code Playgroud)

好处

  • 始终键入安全,因为您不需要使用 any类型
  • 使用 TypeScript 的聚合类型(由&声明类型时的表示objectWithAllProps),它清楚地表明我们正在即时(即动态地)组合一个新类型

需要注意的事项

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


Avi*_*viw 24

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

var obj = {};
obj['prop'] = "value";
Run Code Online (Sandbox Code Playgroud)

  • 这是最简洁的方式。来自 ES6/ES2015 的 `Object.assign(obj, {prop: "value"})` 也可以工作。 (4认同)

小智 23

迟到了,但简单的答案

let prop = 'name';
let value = 'sampath';
this.obj = {
   ...this.obj,
   [prop]: value
};
Run Code Online (Sandbox Code Playgroud)


ibr*_*yel 7

情况1:

var car = {type: "BMW", model: "i8", color: "white"};
car['owner'] = "ibrahim"; // You can add a property:
Run Code Online (Sandbox Code Playgroud)

案例2:

var car:any = {type: "BMW", model: "i8", color: "white"};
car.owner = "ibrahim"; // You can set a property: use any type
Run Code Online (Sandbox Code Playgroud)


Ale*_*lex 7

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

interface MyObject {
    prop1: string;
}

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

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

console.log(newObj.prop2); // 'bar'
Run Code Online (Sandbox Code Playgroud)

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


小智 7

你可以使用这个:

this.model = Object.assign(this.model, { newProp: 0 });
Run Code Online (Sandbox Code Playgroud)

  • 你不需要 `this.model = `。 (2认同)

for*_*d04 7

这是 的一个特殊版本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 }
Run Code Online (Sandbox Code Playgroud)

注意:示例使用了 TS 3.7断言函数。的返回类型assignvoid,与 不同Object.assign


ber*_*ing 5

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

const obj: {[x: string]: any} = {}
obj.prop = 'cool beans'
Run Code Online (Sandbox Code Playgroud)


Dan*_*ich 5

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

  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();
Run Code Online (Sandbox Code Playgroud)


LEM*_*ANE 5

Javascript:

myObj.myProperty = 1;
Run Code Online (Sandbox Code Playgroud)

打字稿:

myObj['myProperty'] = 1;
Run Code Online (Sandbox Code Playgroud)

  • 这是在tsconfig.json上是否为'noImplicitAny:false' (3认同)

Jay*_*ney 5

最简单的将是

const obj = <any>{};
obj.prop1 = "value";
obj.prop2 = "another value"
Run Code Online (Sandbox Code Playgroud)