📌

TypeScript入門 【組み込みユーティリティ&型アサーションと型ガード】

4 min read

今回はTypeScriptの組み込みユーティリティと、型ガードについて説明していきます。

どちらも現場では良く見るコードなので、一緒に学んでいきましょう。

組み込みユーティリティ


まずはジャンル毎に組み込みユーティリティをいくつか紹介します。

オブジェクト型

よく使われるオブジェクト型に使う組み込みユーティリティを次の3つです。

  • Partial …… T のプロパティをすべて省略可能にする
  • Required …… T のプロパティをすべて必須にする
  • Readonly …… T のプロパティをすべて読み取り専用にする

それぞれ以下のように使います。


type nameType = {
  firstName?: string;
  lastName: string;
};
//全て省略可能
const name0: Partial<nameType> = {};
//全て省略不可
const name1: Required<nameType> = {
  firstName: "shiya",
  lastName: "hinohara"
};
//型は元のまま 値の変更が不可になる
const name2: Readonly<nameType> = {
  lastName: "hinohara"
};

また、次の3つも結構使われます。

  • Pick …… T から K が指定するキーのプロパティだけを抽出する
  • Omit …… T から K が指定するキーのプロパティを省く
  • Record …… K の要素をキーとしプロパティ値の型を T としたオブジェクトの型を作成する

それぞれ実際に使うと次のようになります。


type userType = {
  firstName?: string;
  lastName: string;
  type: string;
};
// 元の方からいくつかを取り出せる
const nameProp: Pick<userType, "firstName" | "lastName"> = {
  firstName: "shinya",
  lastName: "hinohara"
};
// Omitでも表現できる
const nameProp2: Omit<userType, "type"> = {
  firstName: "shinya",
  lastName: "hinohara"
};
// number型がプロパティとなり、userTypeをもつ型となります。
type userList = Record<number, userType>;
const users = { 0: { firstName: "taro", lastName: "sato", type: "free" } };

列挙型

次に列挙型に使う組み込みユーティリティをいくつか紹介します。

  • Extract …… T から U の要素だけを抽出する
  • Exclude …… T から U の要素を省く
  • NonNullable …… T から null と undefined を省く

実際に使うと次のようになります。


type hoby = "reading" | "traveling" | null | undefined;
const myHoby: Extract<hoby, "reading"> = "reading";
const myHoby2: Exclude<hoby, "reading"> = "traveling";
const hobies: NonNullable<hoby> = "reading";

後、次の4つも覚えておいて損はないです。

  • Uppercase …… T の各要素の文字列をすべて大文字にする
  • Lowercase …… T の各要素の文字列をすべて小文字にする
  • Capitalize …… T の各要素の文字列の頭を大文字にする
  • Uncapitalize …… T の各要素の文字列の頭を小文字にする


type countries1 = "japan" | "USA" | "chiNese";
// type countries2 = "USA" | "JAPAN" | "CHINESE"
type countries2 = Uppercase<countries1>;
// type countries3 = "japan" | "usa" | "chinese"
type countries3 = Lowercase<countries1>;
// type countries4 = "USA" | "Japan" | "ChiNese"
type countries4 = Capitalize<countries1>;
// type countries5 = "japan" | "chiNese" | "uSA"
type countries5 = Uncapitalize<countries1>;

関数

最後に関数に使う組み込みユーティリティをいくつか紹介します。

  • Parameters …… T の引数の型を抽出し、タプル型で返す
  • ReturnType …… T の戻り値の型を返す

それぞれ実際に使うと


const plus = (num1: number, num2: number): number => {
  return num1 + num2;
};
// type plusType = [num1: number, num2: number]
type plusType = Parameters<typeof plus>;
// type plusReturn = number
type plusReturn = ReturnType<typeof plus>;

型アサーションと型ガード


次に型アサーションと型ガードについて説明します。

型アサーションはas ~と書く事で、コンパイラによる型の解釈が変える手法になります。

このasのはT as (U extends T)または(T extends U) as Uであるとき、つまりTがUのサブタイプであるかUがTのサブタイプである場合にしか使えないものなります。

実際に見ないと良く分からないと思うので、次の例を見てください。


// myCountry=stringとコンパイラに伝える
const myCountry = "japan" as string;
// TがUのサブタイプでもUがTのサブタイプでもないのでエラーになる
const test = 1 as string;

この型アサーションは一見あまり使いどころが内容に思えますが、型ガードをする時に便利です。

型ガードとは、Unknown型を使うための型を保証するチェックのことです。

これも実際に例を見て見ましょう。


const myname: unknown = "taro";
// プリミティブ型(null以外)の型ガードにはtytpeofが使える
if (typeof myname === "string") {
  console.log("hello");
}

class User {
  name: string;
  height: number;
  constructor(name: string, height: number) {
    this.name = name;
    this.height = height;
  }
}
const user1: unknown = new User("taro", 173);
// クラスの型ガードにはinstanceofが使える
if (user1 instanceof User) {
  console.log("hello2");
}

しかし、ただのオブジェクトに対して型ガードしたい時は、自前で型を絞り込むしくみを作ってあげる必要があります。

それは『ユーザー定義の型ガード』と呼ばれる方法で、次の通りです。


type User = { username: string; address: { zipcode: string; town: string } };
const isUser = (arg: unknown): arg is User => {
  const u = arg as User;
  return (
    typeof u?.username === "string" &&
    typeof u?.address?.zipcode === "string" &&
    typeof u?.address?.town === "string"
  );
};
const u: unknown = JSON.parse(
  '{ "username": "patty", "address": { "zipcode": "111", "town": "Maple Town" } }'
);
if (isUser(u)) {
  console.log("heloo");
}

関数 isUser()の戻り値の型定義がarg is Userという見慣れない記述になっていますが、これは型述語という表現で、この関数がtrueを返す場合に引数 argの型がUserであることがコンパイラに伝えることができます。

以上。

また、僕のブログではReactエンジニアになるためのロードマップを無料で全て公開しているので、参考にどうぞ。バックエンドエンジニアを目指している方などにも役立つ情報を書いてます。

https://hinoshin-blog.com/react-roadmap/

おわり

Discussion

ログインするとコメントできます