ウェブサイト検索

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スレッド(例えば、TypeScriptのd.tsファイルで定義されたインターフェースのプロパティ型を上書きする方法のような、インターフェース向けのもの)を読みましたが、必要なものは見つかりませんでした。事前にご回答いただけるとありがとうございます!

回答 #1

各型から 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; })

それは、ユニオン型に対する自動的な分配によるものです

T extends U ? X : Y のインスタンス化において、型引数 A | B | C を T に指定すると、(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y) と解決されます

遊び場


なぜ元の試みはうまくいかないのですか?

「keyof」ユニオンは、ユニオン内の型のキーの交差を生成するので

type AnimalKeys = keyof Animal // is "species" | "owner"

そして Omit の実装は次の通りです:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

回答 #2

私はこれを使って、Reactで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;
}>

エクスポートのためにかなりきれいな一行コードを作ることができます。

関連記事