1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

型ガードというワードは知っていても、どんな時に使うのか?など理解が曖昧だったので調べ直しました。

TypeScriptを理解するための助けになれば幸いです。

型ガードとは?

ある値に対して特定の型であるかチェックし、コードの特定の部分で変数が特定の型を持っていると保証することです。

型を判別する方法

型を判別する方法はいくつかあります。

  • typeof演算子
  • instanceof演算子
  • in演算子

これらを利用してユーザー定義型の型ガードを定義します!

型ガードの方法

本題です。
特定の型であることを保証する方法はいろいろあります。

typeof演算子

typeofはプリミティブ型と呼ばれる基本的な型を判定する際に利用します。

function hoge(value: string | number) {
  if (typeof value === 'string') {
    console.log('string')
  } else {
    console.log('number')
  }
}

nullの場合objectを返すのでその点は注意が必要です…

instanceof演算子

値がクラスオブジェクトのインスタンスであるかどうかを判別して、真偽値を返します。

TypeScript Deep Diveより
class Foo {
  foo = 123;
  common = '123';
}

class Bar {
  bar = 123;
  common = '123';
}

function doStuff(arg: Foo | Bar) {
  if (arg instanceof Foo) {
    console.log(arg.foo); // OK
    console.log(arg.bar); // Error!
  }
  if (arg instanceof Bar) {
    console.log(arg.foo); // Error!
    console.log(arg.bar); // OK
  }

  console.log(arg.common); // OK
  console.log(arg.foo); // Error!
  console.log(arg.bar); // Error!
}

doStuff(new Foo());
doStuff(new Bar());

in演算子

オブジェクトが特定のプロパティを持つかを判定し、真偽値を返します。

サバイバルTypeScriptより
interface Wizard {
  castMagic(): void;
}
interface SwordMan {
  slashSword(): void;
}

function attack(player: Wizard | SwordMan) {
  if ("castMagic" in player) {
    player.castMagic();
  } else {
    player.slashSword();
  }
}

少し話がずれますが、strictNullChecks1を有効にしていると== null or != nullチェックをすることでnullundefinedの両方を排除できます!

ユーザー定義の型ガード関数

ユーザー定義の型ガード関数を作るためには型述語(Type Predicate)を利用します。
Type predicateの宣言は戻り値がboolean型の関数に対して適用できます。

function isDuck(animal: Animal): animal is Duck {
  return animal instanceof Duck;
}

is演算子を使用して、返り値の型を引数名 is 型とします。そして、関数の返り値がtrueの場合、引数名に与えられた値が型に絞り込みます。

関数の返り値の型を動的に制御し、より柔軟な型チェックができます。

型述語の利点

  • 型ガードと組み合わせてより複雑な条件を満たすかどうかをチェックできる
  • 関数の返り値の型を制御し、型エラーを早期発見できコードの安全性を高められる

ユースケースとして、配列からnullやundefinedの型情報を削除する時にユーザー定義型ガードを利用できるとのこと。

const array = [
  "Apple",
  null,
  "Orange",
  undefined,
  "Banana"
]

const filtedArray = array.filter((val) => val != null);
// 型:const filtedArray: (string | null | undefined)[]

上記を下記のように変えると型からnullundefinedを排除できます!

const filtedArray = array.filter((val): val is string => val != null);
// 型:const filtedArray: string[]

ただ、TypeScript5.5からはType Predicateを利用しなくても型をstring[]だと推論してくれます。詳しくは公式のアップデート情報を確認ください!
また、TypeScript5.5のアップデート内容をざっくり把握したい場合は別記事にまとめたのでよろしければご一読ください!

NonNullable

ユーティリティ型のNonNullable<T>を利用することでnullとundefinedを排除できます。

https://www.typescriptlang.org/より
type T0 = NonNullable<string | number | undefined>;
// type T0 = string | number

型ガードの結果を変数に代入できる

TypeScript4.4以降では以下のように型ガードの結果を変数に代入して再利用可能になりました。

function foo(arg: unknown) {
+ const argIsString = typeof arg === "string";
-  if (typeof arg === "string") {
+  if (argIsString) {
    // We know 'arg' is a string now.
    console.log(arg.toUpperCase());
  }
}

まとめ

型安全な状態を保つ方法は色々あるのだと改めて勉強になりました。

現時点で全てを使いこなせる自信はありませんが、こんな方法があるのだと知っているだけでも違うと思うので調べ直して良かったと思います!

参考記事

  1. strictNullChecksはnullやundefinedのチェックを厳しくするコンパイラオプションです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?