如何覆盖 Typescript 中交集类型的属性?

ree*_*ces 18 types typescript .d.ts

假设我有以下类型:

type BaseAnimal = {
  species: string
  owner: boolean
}

type Cat = BaseAnimal & {
  species: 'cat'
  hasTail: boolean
}

type Dog = BaseAnimal & {
  species: 'dog'
  likesWalks: boolean
}

type Animal = Cat | Dog
Run Code Online (Sandbox Code Playgroud)

我想创建一个名为 的类型,除了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
}
Run Code Online (Sandbox Code Playgroud)

现在,我能想到的唯一解决方法是执行以下操作,但这似乎没有必要重复。有没有更干净、更简洁的方法?

type CatParams = Omit<Cat, 'owner'> & {
  owner: string
}

type DogParams = Omit<Dog, 'owner'> & {
  owner: string
}

type AnimalParams = CatParams | DogParams
Run Code Online (Sandbox Code Playgroud)

我读了一些关于实用程序类型的 SO 线程(例如Typescript d.ts 文件中定义的覆盖接口属性类型,用于接口),但找不到我需要的内容。感谢您提前的任何答复!

Ale*_* L. 16

您可以使用分布式条件类型,而不是手动省略owner每种类型的 prop :

type OmitOwner<T = Animal> = T extends BaseAnimal ? Omit<T, 'owner'> : never;

type AnimalParams = OmitOwner & {
  owner: string
};
Run Code Online (Sandbox Code Playgroud)

这相当于:

(Omit<Cat, 'owner'> & { owner: string; }) 
  | (Omit<Dog, 'owner'> & { owner: string; })
Run Code Online (Sandbox Code Playgroud)

这是由于联合类型的自动分配

T extends U ? X : Y使用类型参数A | B | Cfor的实例化解析T(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)

操场


为什么最初的尝试不起作用?

keyofunion 产生 union 中类型键的交集,因此

type AnimalKeys = keyof Animal // is "species" | "owner"
Run Code Online (Sandbox Code Playgroud)

其实现Omit是:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
Run Code Online (Sandbox Code Playgroud)


Hea*_*dJk 7

我一直在使用这个泛型来覆盖 props 并成功做出反应:

type Overwrite<T, NewT> = Omit<T, keyof NewT> & NewT;

export type TouchableAvatarPropTypes = Overwrite<AvatarPropTypes, {
    /** Function executed when avatar is pressed. */
    onPress: () => void;
    /** Size of the avatar */
    size: number;
}>
Run Code Online (Sandbox Code Playgroud)

您可以做一些非常干净的单行文字来导出。


Rob*_*sen 6

如果您确实想坚持使用类型而不是接口,则可以使用泛型来避免重复:

type BaseAnimalParams<T extends BaseAnimal> = Omit<T, 'owner'> & {
    owner: string;
}

type AnimalParams = BaseAnimalParams<Dog> | BaseAnimalParams<Cat>;
Run Code Online (Sandbox Code Playgroud)