如何在 Typescript 中为交集类型覆盖 属性?
How to overwrite property for intersection type in Typescript?
假设我有这些类型:
type BaseAnimal = {
species: string
owner: boolean
}
type Cat = BaseAnimal & {
species: 'cat'
hasTail: boolean
}
type Dog = BaseAnimal & {
species: 'dog'
likesWalks: boolean
}
type Animal = Cat | Dog
我想创建一个名为 AnimalParams
的类型,它与 Animal
除了 owner
属性 相同,它是一个字符串.
以下任何一项我都做不到。
// This seems to keep the owner property from Animal instead of overwriting
// So it raises an error if I try to specify owner as a string
type AnimalParams = Animal & {
owner: string
}
// This strips away properties unique to Cat or Dog
// So it raises an error if I try to specify hasTail or likesWalks
type AnimalParams = Omit<Animal, 'owner'> & {
owner: string
}
现在,我能想到的唯一解决方法是按照以下步骤操作,但这似乎是不必要的重复。有没有更简洁的方法?
type CatParams = Omit<Cat, 'owner'> & {
owner: string
}
type DogParams = Omit<Dog, 'owner'> & {
owner: string
}
type AnimalParams = CatParams | DogParams
我阅读了一些关于实用程序类型的 SO 线程(例如 ,它是针对接口的),但找不到我需要的东西。感谢您提前回答!
如果你真的想坚持类型而不是接口,你可以使用泛型来避免重复:
type BaseAnimalParams<T extends BaseAnimal> = Omit<T, 'owner'> & {
owner: string;
}
type AnimalParams = BaseAnimalParams<Dog> | BaseAnimalParams<Cat>;
您可以使用 distributive conditional type:
而不是手动省略每种类型的 owner
属性
type OmitOwner<T = Animal> = T extends BaseAnimal ? Omit<T, 'owner'> : never;
type AnimalParams = OmitOwner & {
owner: string
};
相当于:
(Omit<Cat, 'owner'> & { owner: string; })
| (Omit<Dog, 'owner'> & { owner: string; })
这是由于联合类型的自动分配
Instantiation of T extends U ? X : Y
with the type argument A | B | C
for T
is resolved as (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)
为什么原来的尝试不起作用?
keyof
union 产生 union 中类型键的交集,所以
type AnimalKeys = keyof Animal // is "species" | "owner"
Omit
的实现是:
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
假设我有这些类型:
type BaseAnimal = {
species: string
owner: boolean
}
type Cat = BaseAnimal & {
species: 'cat'
hasTail: boolean
}
type Dog = BaseAnimal & {
species: 'dog'
likesWalks: boolean
}
type Animal = Cat | Dog
我想创建一个名为 AnimalParams
的类型,它与 Animal
除了 owner
属性 相同,它是一个字符串.
以下任何一项我都做不到。
// This seems to keep the owner property from Animal instead of overwriting
// So it raises an error if I try to specify owner as a string
type AnimalParams = Animal & {
owner: string
}
// This strips away properties unique to Cat or Dog
// So it raises an error if I try to specify hasTail or likesWalks
type AnimalParams = Omit<Animal, 'owner'> & {
owner: string
}
现在,我能想到的唯一解决方法是按照以下步骤操作,但这似乎是不必要的重复。有没有更简洁的方法?
type CatParams = Omit<Cat, 'owner'> & {
owner: string
}
type DogParams = Omit<Dog, 'owner'> & {
owner: string
}
type AnimalParams = CatParams | DogParams
我阅读了一些关于实用程序类型的 SO 线程(例如
如果你真的想坚持类型而不是接口,你可以使用泛型来避免重复:
type BaseAnimalParams<T extends BaseAnimal> = Omit<T, 'owner'> & {
owner: string;
}
type AnimalParams = BaseAnimalParams<Dog> | BaseAnimalParams<Cat>;
您可以使用 distributive conditional type:
而不是手动省略每种类型的owner
属性
type OmitOwner<T = Animal> = T extends BaseAnimal ? Omit<T, 'owner'> : never;
type AnimalParams = OmitOwner & {
owner: string
};
相当于:
(Omit<Cat, 'owner'> & { owner: string; })
| (Omit<Dog, 'owner'> & { owner: string; })
这是由于联合类型的自动分配
Instantiation of
T extends U ? X : Y
with the type argumentA | B | C
forT
is resolved as(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)
为什么原来的尝试不起作用?
keyof
union 产生 union 中类型键的交集,所以
type AnimalKeys = keyof Animal // is "species" | "owner"
Omit
的实现是:
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;