在 Typescript 中动态创建对象

ps0*_*604 7 typescript

下面的 Javascript 代码打印{ x: 1 }

var foo = 'x';
var a = {};
if (foo == 'x')
    a.x = 1;
else
    a.y = 2;
console.log(a);
Run Code Online (Sandbox Code Playgroud)

同样,我需要在 Typescript 中动态构建一个对象,换句话说,当我创建对象时,我不知道它的成员是什么。

我在打字稿中试过这个,但它不起作用:

let foo = 'x';
let a = {};
if (foo == 'x')
    a.x = 1;    //  <-- transpilation fails here
else
    a.y = 2;    //  <-- transpilation fails here 
console.log(a); 
Run Code Online (Sandbox Code Playgroud)

错误是Property 'x' does not exist on type '{}'.是否可以在 Typescript 中动态创建对象?

Tit*_*mir 6

当您声明变量时,TypeScript 需要知道对象将具有的字段。默认情况下,该类型是根据你所指定的它,因为你分配推断{}a将是没有属性的类型。您可以将类型声明为适合a您需要的内容:

var foo = 'x';
var a : { x?: number; y?:number} = {}; // Both x and y are optional, hence the ?
if (foo == 'x')
    a.x = 1;
else
    a.y = 2;
console.log(a);
Run Code Online (Sandbox Code Playgroud)

使用a: any也是一种选择,但您应该避免使用它,因为它会关闭任何a可能不是您想要的检查,因为打字稿的重点是尽可能多地检查。any除非您不知道值的类型和键名,否则我会避免。

如果您在编译时不知道键是什么(也许它们基于用户输入或服务调用),您还可以使用索引签名,至少会检查值的类型是否有效。例如,只允许数字值但任何键的类型如下所示:

var foo = 'x';
var a : { [n: string]: number} = {};
if (foo == 'x')
    a.x = 1;
else
    a.y = 2;
console.log(a);
Run Code Online (Sandbox Code Playgroud)


msa*_*ord 5

如果您确实知道所有可能的字段什么,但不知道将设置哪些字段,则可以使用 a Partial<T>,这避免了您创建新接口并放置在任何地方的需要:?,因为您可能希望从 a 继承其属性并非都是可选的类型/接口:

interface A {
    x: number;
    y: number;
    z: string;
}

let foo = 'x';
let a: Partial<A> = {};
if (foo == 'x')
    a.x = 1;
else
    a.y = 2; 
Run Code Online (Sandbox Code Playgroud)

如果您事先不知道任何字段可以是什么,因为 TypeScript 仅提前存在(在编译阶段),另一个选择是将其声明为类型any

let foo = 'x';
let a: any = {};
if (foo == 'x')
    a.x = 1;
else
    a.y = 2; 
Run Code Online (Sandbox Code Playgroud)

然而,这并不是一个理想的方法,因为它违背了使用 TypeScript 的初衷,因为它完全禁用了类型检查。