我有一个函数,它给了我一个符合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
不同。
有没有办法在保持最大类型安全的同时实现过去的工作?
答案 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>
中一样。