この記事について
この記事は私がTypeScriptについて学んだ内容を
TypeScript①(基礎)
TypeScript②(型の機能)
TypeScript③(ユーティリティタイプ)
の3回に分けて網羅的に紹介していきます。
①(基礎)では導入方法と様々な型について簡単な紹介
②(型の機能)では型が実際にどういう働きをするのかについて
今回は、型変換を容易にするユーティリティ型についてです。
参考リンク
ユーティリティタイプ
TypeScriptは、一般的な型変換を容易にするいくつかのユーティリティ型を提供します。これらのユーティリティはグローバルに利用できます。
Partial型
オブジェクトタイプのすべてのプロパティをオプションにします
interface Todo {
title: string;
description: string;
}
const todo1: Todo = {
title: "foo", // descriptionがないためエラー
};
const todo2: Partial<Todo> = {
title: "foo", // ok
};
Required型
オブジェクトタイプのすべてのプロパティを必須になります
interface Todo {
title?: string;
description?: string;
}
const todo1: Todo = {
title: "foo", // ok
};
const todo2: Required<Todo> = {
title: "foo", // descriptionがないためエラー
};
Readonly型
オブジェクトタイプのすべてのプロパティを読み取り専用にします
interface Todo {
title: string;
description: string;
}
const todo: Readonly<Todo> = {
title: "foo",
description: "bar",
};
todo.title = "fooo"; // 読み取り専用プロパティであるため、'title' に代入することはできません。
Record型
Record<K,T>
キーにK、値にTを持つオブジェクトタイプになります
interface CatInfo {
age: number;
breed: string;
}
type CatName = "miffy" | "boris" | "mordred";
const cats: Record<CatName, CatInfo> = {
miffy: { age: 10, breed: "Persian" },
boris: { age: 5, breed: "Maine Coon" },
mordred: { age: 16, breed: "British Shorthair" },
};
Pick型
Pick<T,K>
型Tの中のプロパティKを持つオブジェクトタイプになります
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, "title" | "completed">;
const todo: TodoPreview = {
title: "Clean room",
completed: false,
};
Omit型
Omit<T, K>
型Tの中のプロパティKを除いたオブジェクトタイプになります
interface Todo {
title: string;
description: string;
completed: boolean;
createdAt: number;
}
type TodoInfo = Omit<Todo, "completed" | "createdAt">;
const todoInfo: TodoInfo = {
title: "Pick up kids",
description: "Kindergarten closes at 5pm",
};
Exclude型
Exclud<T,K>
型Tから型Uと関連するプロパティを除いたオブジェクトタイプになります
type T0 = Exclude<"a" | "b" | "c", "a">; // type T0 = "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // type T1 = "c"
type T2 = Exclude<string | number | (() => void), Function>; // type T2 = string | number
Extract型
Extract<T,K>
型Tと型Kの両方に共通するプロパティだけを持つオブジェクトタイプになります
type T0 = Extract<"a" | "b" | "c", "a" | "f">; // type T0 = "a"
type T1 = Extract<string | number | (() => void), Function>; // type T1 = () => void
NonNullable型
nullとundefinedを除いたオブジェクトタイプになります
type T0 = NonNullable<string | number | undefined>; // type T0 = string | number
type T1 = NonNullable<string[] | null | undefined>; // type T1 = string[]
Parameters型
Parameters<T>
Tに関数型を受け取り、受け取った型をタプル型として持つオブジェクトタイプになります。
declare
はParameters型とは関係ないですが、アンビエント宣言といって関数の型定義を明示的に表したものです。
declare function f1(arg: { a: number; b: string }): void;
type T0 = Parameters<() => string>; // type T0 = []
type T1 = Parameters<(s: string) => void>; // type T1 = [s: string]
type T3 = Parameters<typeof f1>; // type T3 = [arg: { a: number; b: string; }]
ConstructorParameters型
ConstructorParameters<T>
Tにコンストラクタの引数の型をタプル型として持つオブジェクトタイプになります。 Parametersのコンストラクタ版です。
class Foo {
constructor(arg1: string, arg2?: boolean) {}
}
type Bar = ConstructorParameters<typeof Foo>; // [string, boolean] | [string]
ReturnType型
ReturnType<T>
Tで受け取った関数型の戻り型を持つオブジェクトタイプになります
declare function f1(): { a: number; b: string };
type T0 = ReturnType<() => string>; // type T0 = string
type T1 = ReturnType<(s: string) => void>; // type T1 = void
type T4 = ReturnType<typeof f1>; // type T4 = { a: number; b: string; }
InstanceType型
InstanceType<T>
Tで受け取ったコンストラクター関数のインスタンス型を持つオブジェクトタイプになります
class C {
x = 0;
y = 0;
}
type T = InstanceType<typeof C>; // type T = C
ThisParameterType型
Parameters型
ではthis
を受け取れないのに対し、ThisParameterType型
では受け取った関数型のthis
パラメーターの型を持つオブジェクトタイプになります
function fn(this: { a: string }, b: number): string {
return this.a;
}
type T0 = typeof fn;
type T1 = Parameters<T0>; // type Param = [b: number]
type T2 = ThisParameterType<T0>; // type T2 = { a: string; }
OmitThisParameter型
受け取った関数型のthis
パラメーターの型を除いた残りの型を持つオブジェクトタイプになります
declare function fn(this: { a: string; b: boolean }, c: number): void;
type T0 = typeof fn;
type T1 = OmitThisParameter<T0>; // type T1 = (c: number) => void
ThisType型
ThisType<T>
Tのプロパティをthisで扱えるようにします
type ObjectDescriptor<D, M> = {
data?: D;
methods?: M & ThisType<D & M>; // methodsのthisの型がD&Mになります
};
function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
let data: object = desc.data || {};
let methods: object = desc.methods || {};
return { ...data, ...methods } as D & M;
}
let obj = makeObject({
data: { x: 0, y: 0 },
methods: {
moveBy(dx: number, dy: number) {
this.x += dx; // D(dataのプロパティ)がthisで利用できる
this.y += dy;
},
double(dx, dy) {
this.moveBy(dx, dy); // M(methodsのプロパティ)がthisで利用できる
this.moveBy(dx, dy);
},
},
});
obj.double(5, 5);
Uppercase型
文字列内の各文字を大文字に変換します
type Greeting = "Hello, world"
type ShoutyGreeting = Uppercase<Greeting> // type ShoutyGreeting = "HELLO, WORLD"
type ASCIICacheKey<Str extends string> = `ID-${Uppercase<Str>}`
type MainID = ASCIICacheKey<"my_app"> // type MainID = "ID-MY_APP"
Lowercase型
文字列内の各文字を同等の小文字に変換します
type Greeting = "Hello, world"
type QuietGreeting = Lowercase<Greeting> // type QuietGreeting = "hello, world"
type ASCIICacheKey<Str extends string> = `id-${Lowercase<Str>}`
type MainID = ASCIICacheKey<"MY_APP"> // type MainID = "id-my_app"
Capitalize型
文字列の最初の文字を大文字に変換します
type LowercaseGreeting = "hello, world";
type Greeting = Capitalize<LowercaseGreeting>; // type Greeting = "Hello, world"
Uncapitalize型
文字列の最初の文字を小文字に変換します
type UppercaseGreeting = "HELLO WORLD";
type UncomfortableGreeting = Uncapitalize<UppercaseGreeting>; // type UncomfortableGreeting = "hELLO WORLD"
おわりに
今回勉強してきた以外にもTypeScriptにはたくさんの機能や特徴があります。TypeSctipt以外にも学ばないといけないことはたくさんあり、日々更新される変更や追加機能に私自身全くついていけていないですが、焦らず、学びに楽しみを見出しながら続けていきたいと思います。
最後まで読んでいただきありがとうございました。