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

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

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

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

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

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

老丝镜风2020/05/28 14:54:56

最佳做法是使用安全键入,我建议您:

interface customObject extends MyObject {
   newProp: string;
   newProp2: number;
}
Tony凯2020/05/28 14:54:56

这是的特殊版本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 }

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

神乐2020/05/28 14:54:56

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

declare var obj: any;

飞云2020/05/28 14:54:56

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

  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;
Cathy2020/05/28 14:54:56

您可以使用此:

this.model = Object.assign(this.model, { newProp: 0 });
伊芙妮2020/05/28 14:54:56

我很惊讶没有答案引用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),这清楚地表明我们正在动态(即动态)编写新类型

要注意的事情

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

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

  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();
飞云2020/05/28 14:54:56

最简单的将是

const obj = <any>{};
obj.prop1 = "value";
obj.prop2 = "another value"
老丝阿飞2020/05/28 14:54:55

或一劳永逸:

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