我正在尝试创建类型映射器NewRecord<T>
,该类型映射器将从id
中剥离<T>
类型。
我就是这样的:
type NewRecord<T> = {
[P in Exclude<keyof T, 'id'>]: T[P]
}
但是,不幸的是,它不适用于联合类型。让我举例说明:
interface IRecord {
id: number
}
interface IBotRecord extends IRecord {
isBot: true
cpuCores: 4
}
interface IHumanRecord extends IRecord {
isBot: false
isHungry: true
}
type ICreature = IHumanRecord | IBotRecord
type INewBotRecord = NewRecord<IBotRecord>
type INewHumanRecord = NewRecord<IHumanRecord>
type INewCreature = NewRecord<ICreature>
const newHuman:INewHumanRecord = {
isBot: false,
isHungry: true // works!
}
const newCreature:INewCreature = {
isBot: false,
isHungry: true // does not exist in type NewRecord<ICreature>
}
之所以会这样,是因为keyof
在类型的交集而不是并集上进行迭代,并且该行为是预期的:https://github.com/Microsoft/TypeScript/issues/12948
从联合中剥离字段的正确方法是什么?
答案 0 :(得分:4)
您要为联合的每个成员应用映射类型。幸运的是,条件类型具有这种确切的行为,它们分布在裸类型参数上。这意味着映射类型将独立应用于联合的每个成员,并且所有结果都将合并为最终类型。有关更多说明,请参见here和here。
在这种情况下,条件类型中的条件可以只是extends any
,我们不在乎条件部分,我们只在乎条件类型的分布行为:
type NewRecord<T> = T extends any ? {
[P in Exclude<keyof T, 'id'>]: T[P]
} : never
type INewCreature = NewRecord<ICreature>
// The above type is equivalent to
type INewCreature = {
isBot: false;
isHungry: true;
} | {
isBot: true;
cpuCores: 4;
}
const newCreature:INewCreature = {
isBot: false,
isHungry: true // works fine
}