TypeScriptで実装をしてると、特定の型の変数プロパティだけ抽出した型を指定したくなることがたまにあります。
そういうときに使えるUtility Typesをつくりました。
前提
例えば次のようなクラスAがあって、コンストラクタの引数は自身と同じインターフェイスを持つオブジェクトにしたいとき、クラスAの持つメソッドも引数に指定しないといけません。
class A {
a: string;
constructor(v: A) {
this.a = v.a;
}
func () {
//
}
}
const c = new A({
a: 'a',
func: () => {}, // これはよくないので無くしたい
});
でもメソッドまで実際の引数に指定するのは無駄なので、メンバ変数だけを指定したくなります。
このクラスAの場合はメンバ変数が1つなので
constructor(v: { a: string }) {
このようにコンストラクタを指定してもいいですがメンバ変数が増えていくと辛い…
さてどうしましょ。
Utility Typesを定義する
Utility TypesでクラスAからメンバ変数のaだけを抽出するようなものを実装します。
type NonFuncPropNames<T> = {
[K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];
type NonFuncProps<T> = Pick<T, NonFuncPropNames<T>>;
変数プロパティを抽出すると書いておきながら、実際はジェネリクスで指定された型から関数プロパティを除去してます。
なので名前もNonFuncProps
。
こまけえこたぁ(略
実装を修正
で、このNonFuncProps
にクラスAを指定すると最初のサンプルは次のように書けます。
class A {
a: string;
constructor(v: NonFuncProps<A>) {
this.a = v.a;
}
func () {
//
}
}
const c = new A({
a: 'a',
});
こんな感じでメソッドは書かなくてよくなりました。
これでクラスにたくさんメンバ変数が増えても安心ですね。
もちろんこのUtility Typesはインターフェイスとかにも適用できます。あー便利