我可以增量构建一个实现接口的对象吗?

Can I incrementally build an object that implements an interface?

我的界面如下:

export interface Person {
  name: string;
  isMillenial: boolean;
}

以及输出该接口的函数,如:

function makePerson(name: string, birthYear: number): Person {
  let newPerson = {
    name
  }

  // Calculate various properties, slowly building up the `newPerson` object
  newPerson.isMillenial = birthYear < 1981

  return newPerson
}

然而,这将失败并出现如下错误:

Property 'isMillenial' is missing in type '{ name: string }' but required in type 'Person '.

我知道我可以在创建它时声明 newPerson 的所有属性,以符合预期 - 但 我想构建我正在创建的对象,添加属性直到对象完成。 有没有一种方法可以在 TypeScript 中增量构建对象,同时仍然满足类型检查?

(如果答案是'no, you need defaults',那是可以接受的答案)

是的,但是您必须以不同的方式声明它,并且您可能必须在完成对象时告诉 TypeScript。 Partial utility type 创建一个基于另一种类型的类型,使其所有属性都是可选的。所以:

function makePerson(name: string, birthYear: number): Person {
    let newPerson: Partial<Person> = {
    // −−−−−−−−−−−−^^^^^^^^^^^^^^^
        name
    };

    // Calculate various properties, slowly building up the `newPerson` object
    newPerson.isMillenial = birthYear < 1981;

    return newPerson as Person;
    // −−−−−−−−−−−−−−^^^^^^^^^
}

可悲的是最后的类型断言是必要的(这让我感到惊讶,你可以从上面看出 属性 到最后都不会是 undefined,但是 TypeScript 团队必须把限制编译器的智能程度以防止它变得非常慢)。

Playground link

return 上的 as Person 也意味着您可以根据需要将其从函数声明签名中删除,TypeScript 将知道函数的 return 类型:

function makePerson(name: string, birthYear: number): Person {
// Optional as far as TypeScript is concerned −−−−−−^^^^^^^^

...尽管如果函数不止几行,您可能希望将它留在那里,以确保您不会在其他地方添加新的 return 来更改 return类型。


你在问题中提到了它,但我会强调它只是因为它的价值(和潜伏者)你可以建立你将用于创建对象的信息,然后创建对象一次全部保存以保存需要类型注释。这简化了示例,当然实际代码可能不会变得更简单:

function makePerson(name: string, birthYear: number): Person {
    const isMillenial = birthYear < 1981;
    return {name, isMillenial};
}

这并不总是可行,但我发现它很有用。