TypeScriptで継承したinterfaceのプロパティを一部上書きする方法
やっていいかは別として
バグの原因になるとか、OOPに反するとかいろいろあるけれど、interfaceをextendsして継承元にあるプロパティを一部だけ上書きして別のプロパティにしたいみたいな気持ちになることがある(と思う)。
おさらい
interface Aがあってそれを継承するinterface Bがあるとする
interface A { foo: number bar: number baz: number qux: number yo: number } interface B extends A { cha: string }
これは普通に通る例
このinterface Bは実質こういう状態
interface B { foo: number bar: number baz: number qux: number yo: number cha: string }
OKですね。
プロパティを上書きしたいんだよね
yoプロパティの型を継承した上でB独自にyoだけ型を変更したい。
interface A { foo: number bar: number baz: number qux: number yo: number } interface B extends A { cha: string yo: string // Aにある"yo"はnumber型だがBではstring型にしたい }
これできそうな気がするけどやるとエラーになって
インターフェイス 'B' はインターフェイス 'A' を正しく拡張していません。
プロパティ 'yo' の型に互換性がありません。
型 'string' を型 'number' に割り当てることはできません。
と言われてしまう。
ハック技で実現できる
中継型を経由すれば実現可能
中継型で上書きしたいプロパティを一度anyにする
interface A { foo: number bar: number baz: number qux: number yo: number } // weakな中継用のinterfaceを用意する interface Bweaken extends A { yo: any } interface B extends Bweaken { cha: string yo: string }
yoプロパティを変更したいので中継型Bweakenでyoを一度anyにしておけばBでAを継承しつつプロパティを上書きできる
Util
type Weaken<T, K extends keyof T> = { [P in keyof T]: P extends K ? any : T[P] }
こういうのべんり君を用意すると
interface B extends Weaken<A, 'yo'> { cha: string yo: string }
便利っぽい。