目次
序文
この記事はTypeScript 知識のまとめ記事シリーズに含まれています。修正は歓迎です。
前の記事では、ジェネリックの使用法を一般的に理解し、ジェネリックを通じて一般的に使用されるいくつかの型を実装しました。次に、この記事では、一般的に使用されるいくつかのジェネリック ツール タイプの使用と実装について詳しく理解します。それでは、これ以上面倒な作業はせずに、直接始めましょう。
部分的<T>
Partial<T> の役割は、型 T のすべての属性をオプションの属性に変えることです。
interface IAnimal {
name: string
age: number
color: string
}
type MyPartial = Partial<IAnimal>
に変換するのと同じです
type MyPartial = {
name?: string;
age?: number;
color?: string;
}
その実装では、マッピング タイプを使用してオブジェクトのプロパティをトラバースします。
type Partial<T> = {
[P in keyof T]?: T[P];
};
必須<T>
Required は Partial の逆です。その機能は、すべての属性を必須属性に変えることです。使用される原則は「-?」記号です。
type MyRequired = Required<MyPartial>
上記のコードの MyRequired は IAnimal に戻ります。以下は Required の実装です。
type Required<T> = {
[P in keyof T]-?: T[P];
};
読み取り専用<T>
読み取り専用属性前の記事でも説明しましたが、すべての属性を読み取り専用に置き換えます。
type MyReadonly = Readonly<MyRequired>
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
ピック<T, K>
Pick の機能は、オブジェクト内のいくつかの属性を選択することです。たとえば、名前と年齢を選択します。
type MyPick = Pick<IAnimal, "name" | "age">
彼の実装プロセスでは、2 つの型パラメーターを渡します。1 つ目はオブジェクト型、2 つ目は属性コレクションです。
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
<T, U> を除く
Exclude<T, U> は、U 型または型コレクションを T から除外することを意味します。たとえば、次のコードは文字列型を除外します。
type MyExclude = Exclude<string | number | boolean, string>
さらに、Exclude をオブジェクト タイプに統合して、次のような属性値を除外できます。
type ExcludeAnimal = {
[key in Exclude<keyof IAnimal, string>]: IAnimal[key]
}
上記のコードは、IAnimal 内のすべての文字タイプの属性名を除外すること、つまりすべての属性をクリアすることを実現します。
除外の実装
type Exclude<T, U> = T extends U ? never : T;
<T,K>を省略
Omit<T, K> の意味は、T オブジェクト タイプから K を削除することです。たとえば、IAnimal の年齢と色を削除できます。
type OmitAnimal = Omit<IAnimal, "age" | "color">
その実装は Pick+Exclude によっても実現されますが、次の 2 つの手順を覚えておいてください: Exclude は T の K の型を除外し、戻り値は Pick に渡されます。Pick を使用して新しいオブジェクト タイプを生成します。
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
レコード<K, T>
レコードは、オブジェクト内の属性のバッチ作成として理解できます。ここで、キー値またはそのコレクションは K、タイプは T です。上記の IAnimal を表すために Record を使用します
type RecordAnimal = Record<"name" | "color", string> & Record<"age", number>
実装は次のとおりです。ここで、P はオブジェクトの属性を表す K のサブセットです。
type Record<K extends keyof any, T> = {
[P in K]: T;
};
実際、上記のコードを次のように記述して、文字列 | 数値 | 記号のコレクションを通じてキーのセキュリティを確保できます。
type IRecord<K extends string | number | symbol, T> = { [key in K]: T }
Null 不可<T>
NonNullable<T> は通常、型 T から空の型を除外する、つまり null か未定義があるかを判断し、存在しない場合は元の型を返すために使用されます。
NonNullable<null | undefined | string | boolean | number> // 表示 string | number | boolean
型の実装
type NonNullable<T> = T extends null | undefined ? never : T;
戻り値の型<T>
ReturnType は関数の戻り値の型を取得するために使用されます。T は関数の型を表します
type foo<T> = (params: T) => T[]
type IReturnType = ReturnType<foo<string>>
関数が呼び出されない場合、ジェネリック型を取得できず、この時点で ReturnType を使用すると不明な型が取得されます。
function foo<T>(params: T) {
return [params]
}
type IReturnType = ReturnType<typeof foo> // unknown[]
ReturnType の実装では、前の記事で説明した infer キーワードを使用する必要があります。
return 関数の戻り値の型がどのように実装されているかを確認してみましょう。
type IReturn<T> = T extends (...args: any[]) => infer R ? R : T;
type foo = () => string
type IReturnType = IReturn<foo>// string
次に、ジェネリックスに制約を追加します。ジェネリックスは関数型のみを渡すことができます。
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
このようにして関数の戻り値を取得する型が実装されます
パラメータ<T>
関数の戻り値の型の取得について説明した後、Parameters<T> を見て関数のパラメーターの型を取得し、関数 T を渡して T のパラメーターの型を取得します。
type foo<T> = (params: T) => T
type IGetParameters = Parameters<foo<string>>// [params: string]
パラメーターの型は引数の配列に似ています。次のコードを考慮して、関数のパラメーターの型を取得するには infer を使用します。
type IParameters<T> = T extends (...args: infer P) => any ? P : T;
関数の戻り値と同様に、関数制約を追加することで完全な機能を実現できます。
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
コンストラクターパラメータ<T>
ConstructorParameters は、コンストラクター T のパラメーターの型を取得することを意味します。インターフェイスを使用してクラス コンストラクターを定義し、ConstructorParameters を通じてそのパラメーターの疑似配列を取得します。
interface IAnimal {
new(name: string, age: number)
}
type getConstructorParameters = ConstructorParameters<IAnimal> // [name: string, age: number]
実装はパラメータと似ていますが、関数の型がクラスに置き換えられる点が異なります。
type IConstructorParameters<T> = T extends new (...args: infer P) => any ? P : never;
ヒント: この型の公式実装には優れた点があります。つまり、型は抽象クラスを使用して実装されます。理由は何ですか?次のコードを見てみましょう
// 抽象类
abstract class Animal { }
// 类
class Dog { }
// 使用类类型实现获取构造函数参数类型
type ICParameters<T> = T extends new (...args: infer P) => any ? P : never;
// 使用抽象类类型实现获取构造函数参数类型
type IAbstractCParameters<T> = T extends abstract new (...args: infer P) => any ? P : never;
// 抽象类类型-抽象类
type getAbstractCParametersAnimal = IAbstractCParameters<typeof Animal>// []
// 抽象类类型-类
type getAbstractCParametersDog = IAbstractCParameters<typeof Dog>// []
// 类类型-抽象类
type getCParametersAnimal = ICParameters<typeof Animal>// never
// 类类型-类
type getCParametersDog = ICParameters<typeof Dog>// []
抽象クラスはクラスによってのみ継承できますが、その逆はできないことがわかります。前に述べたクラスに関する記事をまだ覚えていますか? 抽象クラスは継承のみが可能であり、インスタンス化はできず、クラスまたは抽象クラスによってのみ継承できます。したがって、抽象クラスを使用してコンストラクター パラメーターの型を取得することは抽象クラスに適用できますが、クラスを使用してコンストラクター パラメーターの型を取得することは抽象クラスに適用できないことが理解されます。説明が雑なので参考程度にしてください、コードを見てみるとわかりやすいです
最後に、上記に基づいて、次のコードによって完全な型を実現するために、ConstructorParameters 型に抽象クラス制約を追加します。
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;
インスタンスタイプ<T>
InstanceType は、クラスのインスタンス化タイプ、つまり新しいクラスの生成物を取得するために使用されます。これは、上記の ConstructorParameters タイプに対応する、実行コンストラクターの戻り値と言えます。
class Animal {
constructor(name?: string, age?: number) { }
}
const animal: InstanceType<typeof Animal> = new Animal()
実装方法も同様なので省略します
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
ThisParameterType<T>
ThisParameterType は関数パラメータの this の型を取得し、call、apply、bind でよく使用されます。
function getThis(this: any) {
console.log(this);
}
type getThisType = ThisParameterType<typeof getThis>;// string
しかし同時に、関数内の最初のパラメータに this という名前が付けられていない限り、この型は不明であることを意味します。
function getThis(str: string) {
console.log(str);
}
type getThisType = ThisParameterType<typeof getThis>;// unknown
ヒント: コンパイルされた関数の最初のパラメータは消えます
function getThis() {
console.log(this);
}
これを達成する方法は、関数のこのパラメータの最初のタイプを取得することです。
type ThisParameterType<T> = T extends (this: infer U, ...args: never) => any ? U : unknown;
このパラメータを省略<T>
OmitThisParameter の目的は、関数の最初のパラメーターが次の場合にそれを削除し、関数の型を返すことです。
function getThis(this: string) {
console.log(this);
}
type getThisType = OmitThisParameter<typeof getThis>;// () => void
その実装は次のとおりです
type OmitThisParameter<T> = T extends (this: any, ...args: infer P) => infer R ? (...args: P) => R : T;
最後に書きます
上記が記事の全内容です。この記事では、一般的に使用される汎用ツール タイプを詳細に解釈して実装しました。ご質問があれば、さらにアドバイスをお願いします。最後まで読んでいただき、ありがとうございます。記事が役に立った場合は、サポートをお願いします。ありがとうございます!