0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

個人的アウトプットカレンダーAdvent Calendar 2024

Day 24

【TypeScript】ユーザー定義型ガードについて

Last updated at Posted at 2024-12-24

O'Reilly のプログラミングTypeScriptを読んでいると、
ユーザー定義型ガード」なるものが出てきました。

今まで使用したことがなく気になったため、
今回はこのユーザー定義型ガードについてまとめます。

ユーザー定義型ガードとは

ユーザー定義型ガードは、開発者が独自に定義できる型チェックの仕組みで、
特定の条件下で変数の型を具体的に絞り込むことができます。

以下の形式で定義します。

function isType(arg: any): arg is SpecificType {
  // 型チェックのロジック
  return // boolean
}

arg is SpecificType という個所が重要で、
この関数が true を返した場合、argSpecificType として扱われます。

使用例

ここではユーザー定義型ガードの使用例をみてみましょう。

ユーザー権限判断

この例ではユーザーの権限が admin guest どちらなのかを判断しています。

interface Admin {
  role: 'admin';
  privileges: string[];
}

interface Guest {
  role: 'guest';
}

type User = Admin | Guest;

function isAdmin(user: User): user is Admin {
  return user.role === 'admin';
}

const user: User = { role: 'admin', privileges: ['manage-users'] };

if (isAdmin(user)) {
  console.log(user.privileges); // Admin型のプロパティにアクセス可能
} else {
  console.log('User is a guest');
}

通常の型ガードとの比較

通常の型ガードとも比較してみましょう
下記は、型 CircleRectangle を判断する例です。

型定義
interface Shape {
  type: string;
}

interface Circle extends Shape {
  type: 'circle';
  radius: number;
}

interface Rectangle extends Shape {
  type: 'rectangle';
  width: number;
  height: number;
}

通常の型ガード

typeof を使用した場合

typeof はプリミティブ型にしか対応していないため、具体的な型を絞り込むことはできません。

const isCircle = (shape: Shape): boolean => {
  if (typeof shape === 'circle') {
    // エラー: `typeof`では"circle"のようなカスタム型は判定できない
    return true;
  }
  return false;
};

instanceof を使用した場合

instanceof はクラスインスタンスを判定するものですが、ここでは interface を使用しているため、instanceof は適用できません。

const isCircle = (shape: Shape): boolean => {
  if (shape instanceof Circle) {
    // エラー: `Circle`はインターフェースのため `instanceof`は使用できない
    return true;
  }
  return false;
};

ユーザー定義型ガード

以下のようにCircleRectangle を判定する関数を作成できます。

function isCircle(shape: Shape): shape is Circle {
  return shape.type === 'circle' && 'radius' in shape && typeof shape.radius === 'number';
}

function isRectangle(shape: Shape): shape is Rectangle {
  return shape.type === 'rectangle' && 'width' in shape && 'height' in shape;
}

const printShapeInfo = (shape: Shape) => {
  if (isCircle(shape)) {
    console.log(`Circle with radius: ${shape.radius}`);
  } else if (isRectangle(shape)) {
    console.log(`Rectangle with width: ${shape.width}, height: ${shape.height}`);
  } else {
    console.log('Unknown shape');
  }
};

const circle: Circle = { type: 'circle', radius: 5 };
const rectangle: Rectangle = { type: 'rectangle', width: 10, height: 20 };

printShapeInfo(circle); // Circle with radius: 5
printShapeInfo(rectangle); // Rectangle with width: 10, height: 20

おわりに

typeofinstanceof では、基本型の判定しかできません。
ユーザー定義型ガード を使用することで、type やその他のプロパティの条件を基に型を判定でき、非常に便利だなと思いました。

それでは。

参考文献

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?