在TypeScript 2.4中使用部分类型替换

时间:2017-06-19 13:27:07

标签: typescript typescript2.4

我有一个函数,它给了我一个符合Person接口的夹具:

interface Person {
  name: string
  email: string
  age?: number
}

function makePerson(override: Partial<Person> = {}): Person {
  return {
    name: 'Jim',
    email: 'jim@example.com,
    age: 24,
    ...override,
  }
}

在TypeScript 2.3中,这可以正常工作;我可以调用这样的函数来覆盖某个键:

const myPerson = makePerson({name: 'Bob'})
// {
//   name: 'Bob',
//   email: 'jim@example.com,
//   age: 24,
// }

但是,更新到2.4之后,编译器现在会出现如下错误:

Type '{ name: string | undefined; email: string | undefined; age: number | undefined; }' is not assignable to type 'Person'.
  Types of property 'name' are incompatible.
    Type 'string | undefined' is not assignable to type 'string'.
      Type 'undefined' is not assignable to type 'string'.

我可以看到它为什么这样做 - 在JavaScript中,可以通过将一个或多个键设置为undefined的对象传入来覆盖对象中的任何键,这将覆盖默认值和结果在函数中返回不符合Person的对象。这是因为省略键与设置undefined不同。

有没有办法在保持最大类型安全的同时实现过去的工作?

2 个答案:

答案 0 :(得分:2)

这可能不是最好的答案,但你可以通过避免对象传播和设置每个单独的字段来绕过它。

function makePerson(override: Partial<Person> = {}): Person {
  return {
    name: override.name !== undefined ? override.name : 'Jim',
    email: override.email !== undefined ? override.email : 'jim@example.com',
    age: override.age !== undefined ? override.age : 24
  }
}

答案 1 :(得分:0)

这个答案至少看起来只是像理论一样 - 但它有效。

将该类型视为一组属性,并且您希望能够使用这些属性的任何给定子集调用makePerson - 所有属性的 power set 。类型可以表示:

type Person_Powerset = 
    {} |
    {email: string} | { name: string }  | { age: number} |
    {name: string, email: string} | {name: string, age: number} | {email: string, age: number} |
    {name: string, email: string, age: number};

我不知道TypeScript在类型级别是否足够表达以允许构造此类型,例如就像在Powerset<Person>中一样。