⚒️

【TypeScript】ユーティリティ型を整理してみる

2022/04/25に公開

どうもフロントエンドエンジニアのoreoです。

今回は、ユーティリティ型について整理してみたいと思います。いつも同じようなユーティリティ型を使っていますが調べてみるとたくさんありますね。

1 ユーティリティ型とは?

TypeScriptで用意されている型変換が簡単にできる型です。ユーティリティ型では、前回の記事で紹介したGenerics型が利用されています。型をよしなに変換してくれる便利ツールのようなイメージです!

2 ユーティリティ型

公式ドキュメントに記載されているユーティリティ型を整理していきます。

2-1 Partial<Type>

Partial<Type>は、typeの全てのプロパティをオプショナルにします。

type CustomerData = {
  name: string;
  age?: number;
  gender?: string;
  department?: string;
  isRetired: boolean;
};

type PartialCustomerData = Partial<CustomerData>;

このPartialCustomerDataは、👇と同じです。

type PartialCustomerData = {
  name?: string;
  age?: number;
  gender?: string;
  department?: string;
  isRetired?: boolean;
};

2-2 Required<Type>

Required<Type>は、typeの全てのプロパティを必須にします。

type CustomerData = {
  name: string;
  age?: number;
  gender?: string;
  department?: string;
  isRetired: boolean;
};

type RequiredCustomerData = Required<CustomerData>;

このRequiresCustomerDataは、👇と同じです。

type RequiredCustomerData = {
  name: string;
  age: number;
  gender: string;
  department: string;
  isRetired: boolean;
};

2-3 Readonly<Type>

Readonly<Type>は、typeの全てのプロパティを読み取り専用にします。更新などができなくなりますね。

type CustomerData = {
  name: string;
  age?: number;
  gender?: string;
  department?: string;
  isRetired: boolean;
};

type ReadonlyCustomerData = Readonly<CustomerData>;

👇プロパティの更新ができなくなります。

const customerData: ReadonlyCustomerData = {
  name: "shinji",
  age: 28,
  gender: "male",
  department: " accounting",
  isRetired: false,
};

//読み取り専用プロパティであるため、'name' に代入することはできません。
customerData.name = "asuka";

2-4 Record<Keys, Type>

Reacord<keys,Type>は、プロパティのキーがkeysでその型がTypeであるオブジェクト型を返します。

type CustomerLists = Record<"shinji" | "asuka", CustomerData>;

const customerlists: CustomerLists = {
  shinji: {
    name: "shinji",
    age: 28,
    gender: "male",
    department: "accounting",
    isRetired: false,
  },
  asuka: {
    name: "asuka",
    age: 28,
    gender: "female",
    department: "sales",
    isRetired: false,
  },

CustomerListsの型は👇のようになります。

type CustomerLists = {
    shinji: CustomerData;
    asuka: CustomerData;
}

2-5 Pick<Type, Keys>

Pick<Type,Keys>は、型TypeからKeysで指定したキーを含むオブジェクト型を返します。

type CustomerData = {
  name: string;
  age?: number;
  gender?: string;
  department?: string;
  isRetired: boolean;
};

type CustomerNameLists = Pick<CustomerData,"name">

CustomerNameListsの型は👇のようになります。

type CustomerNameLists = {
    name: string;
}

2-6 Omit<Type, Keys>

Omit<Type,Keys>は、型TypeからKeysで指定したキーを除くオブジェクト型を返します。

type CustomerData = {
  name: string;
  age?: number;
  gender?: string;
  department?: string;
  isRetired: boolean;
};

type CustomerNameLists = Omit<
  CustomerData,
  "age" | "gender" | "department" | "isRetired"
>;

CustomerNameListsの型は👇のようになります。

type CustomerNameLists = {
    name: string;
}

2-7 Exclude<UnionType, ExcludedMembers>

Exclude<UnionType, ExcludedMembers>は、ユニオン型UnionTypeから、ExcludedMembersで指定した型を除いたユニオン型を返します。

type JobGrade = "S" | "A" | "B" | "C" | "D";
type SuperJobGrade = Exclude<JobGrade, "B" | "C" | "D">;

SuperJobGradeの型は👇のようになります。

type SuperJobGrade = "S" | "A"

2-8 Extract<Type, Union>

Extract<Type, Union>は、ユニオン型Typeから、Unionで指定した型を抽出したユニオン型を返します。

type JobGrade = "S" | "A" | "B" | "C" | "D";
type SuperJobGrade = Extract<JobGrade, "S" | "A">;

SuperJobGradeの型は👇のようになります。

type SuperJobGrade = "S" | "A"

Extract<Type, Union>は、2つのユニオン型の共通部分を抽出するのに使えます。

2-9 NonNullable<Type>

NonNullable<Type>は、Typeから、nullundefiendと取り除いた型を返します。

type T1 = string | boolean | null | undefined;
type NonNullableT1 = NonNullable<T1>;

NonNullableT1の型は👇のようになります。

type NonNullableT1 = string | boolean

2-10 Parameters<Type>

Parameters<Type>は、関数型Typeの引数をタプル型として抽出した型を返します。

type T1 = Parameters<
  (arg1: string, arg2: boolean, arg3?: number) => void
>;

T1は、👇と同じです。

type T1 = [arg1: string, arg2: boolean, arg3?: number | undefined]

2-11 ConstructorParameters<Type>

ConstructorParameters<Type>は、コンストラクター関数型Typeの引数をタプル型として抽出した型を返します。

class Customer {
  name: string;
  age: number;
  isRetired: boolean;
  constructor(name: string, age: number, isRetired: boolean) {
    this.name = name;
    this.age = age;
    this.isRetired = isRetired;
  }
}

type ConstructorParametersCustomer = ConstructorParameters<typeof Customer>;

ConstructorParametersCustomerは、👇と同じです。

type ConstructorParametersCustomer = [name: string, age: number, isRetired: boolean]

2-12 ReturnType<Type>

ReturnType<Type>は、関数型Typeの返り値の型を抽出します。

type T1 = ReturnType<() => string | number>;

T1は、👇と同じです。

type T1 = string | number

2-13 InstanceType<Type>

InstanceType<Type>は、コンストラクタで生成されるインスタンスの型を返します。

class Customer {
  name: string;
  age: number;
  isRetired: boolean;
  constructor(name: string, age: number, isRetired: boolean) {
    this.name = name;
    this.age = age;
    this.isRetired = isRetired;
  }
}

type T1 = InstanceType<typeof Customer>;

T1は、👇と同じになります。

type T1 = Customer

2-14 ThisParameterType<Type>

ThisParameterType<Type>は、this引数の型を取得できます。

type T1 = ThisParameterType<
  (this: { name: string; age: number }, arg: string) => void
>;

T1は、👇のようになります。

type T1 = {
    name: string;
    age: number;
}

ちなみに、2-10で紹介したParameters<Type>では、this引数の型は取得できません。

type T2 = Parameters<
  (this: { name: string; age: number }, arg: string) => void
>;

T2は、👇のようになります。

type T2 = [arg: string]

2-15 OmitThisParameter<Type>

OmitThisParameter<Type>は、this引数の型を取り除いた関数型を取得できます。

type T1 = OmitThisParameter<
  (this: { name: string; age: number }, arg: string) => void
>;

T1は、👇のようになります。

type T1 = (arg: string) => void

2-16 ThisType<Type>

ThisType<Type>は、object内でのthisの型をTypeを定義します。

const obj: ThisType<{ name: string; age: number }> = {
  info() {
    console.log(this.name, this.age);
  },
};

obj内でのthisは、👇のようになります。

this: {
    name: string;
    age: number;
}

2-17 Uppercase<StringType>

文字列のリテラル型を全て大文字にして返します。

type name = Uppercase<"Shinji">;
//type name = "SHINJI" となる

2-18 Lowercase<StringType>

文字列のリテラル型を全て小文字にして返します。

type name = Lowercase<"SHINJI">;
//type name = "shinji"となる

2-19 Capitalize<StringType>

文字列のリテラル型を最初の文字を大文字にして返します。

type name = Capitalize<"shinji">;
//type name = "Shinji"となる

2-20 Uncapitalize<StringType>

文字列のリテラル型を最初の文字を小文字にして返します。

type name = Uncapitalize<"SHINJI">;
//type name = "sHINJI"となる

3 最後に

PartialRequiredReadonlyRecordPickOmitくらいまでは普段の使うことがありましたが、その他のものは馴染みがありませんでした。

特に、this絡みのユーティリティ型は、あまり使い所がイメージできていないので、OSSでの使われ方を探してみる、またはtype-challengesなどで、理解を深めていきたいです!

4 参考

Documentation - Utility Types

ユーティリティ型 (utility type) | TypeScript入門『サバイバルTypeScript』

TypeScript 4.1で密かに追加されたintrinsicキーワードとstring mapped types

TypeScriptの"型"を学びたいあなたへ。type-challengesのすゝめ - Qiita

Discussion