TypeScript 速習チュートリアル

TypeScript の特殊な型

TypeScriptには、型システムにおいて特定の振る舞いを持ついくつかの特殊な型(Special Types)が含まれています。
これらの型は、型が事前に判明していないケースや、JavaScriptのプリミティブを型安全(Type-safe)な方法で扱う必要があるさまざまなシナリオで使用されます。

       注意: これらの特殊な型はTypeScriptの型システムの一部であり、コードの型安全性を高め、自己文書化(Self-documenting)を助ける役割を果たします。

1. any 型

any 型は、TypeScriptにおいて最も柔軟な型です。
本質的には、特定の変数に対してタイプチェック(Type checking)をスキップするようコンパイラに指示します。

特定の状況では便利ですが、TypeScriptの型安全機能の多くをバイパスしてしまうため、使用は最小限にとどめるべきです。

1.1 any を使用する場面

  • JavaScriptのコードをTypeScriptに移行する場合
  • 型が不明な動的コンテンツ(Dynamic content)を扱う場合
  • 特定のケースで意図的に型チェックを無効化したい場合

以下の例は any を使用していないため、エラーが発生します。

例:any なし(エラー発生)

let u = true;
u = "string"; // エラー: 型 'string' を型 'boolean' に割り当てることはできません。
Math.round(u); // エラー: 型 'boolean' の引数を型 'number' のパラメータに割り当てることはできません。

変数を特殊な型 any に設定すると、タイプチェックが無効になります。

例:any あり

let v: any = true;
v = "string"; // any型なのでエラーになりません
Math.round(v); // any型なのでエラーになりません

any はタイプチェックを無効にするためエラーを回避する便利な方法に見えますが、TypeScriptによる型安全性は提供されず、オートコンプリート(入力補完)などの型データに依存するツールの機能も動作しなくなります。

「いかなる(any)」コストを払っても、any の多用は避けるべきであることを覚えておいてください。

2. unknown 型

unknown 型は、any に対する型安全なカウンターパート(対応する型)です。
「これは何にでもなり得るが、使用する前に何らかの型チェックを行う必要がある」ということを型安全に伝えるための方法です。

2.1 unknown と any の主な違い

  • unknown は使用前に型チェック(Type-check)が必要。
  • 型アサーション(Type assertion)なしでは unknown 型のプロパティにアクセスできない。
  • unknown 型の値を呼び出したり、コンストラクトしたりすることはできない。

TypeScriptは、以下の例のように適切な型チェックなしで unknown 型が使用されるのを防ぎます。

例:unknown の利用

let w: unknown = 1;
w = "string"; // エラーなし

w = {
  runANonExistentMethod: () => {
    console.log("我思う、ゆえに我あり");
  }
} as { runANonExistentMethod: () => void };

// 型が不明なとき、以下のコメントアウトされたコードのエラーをどう回避すべきか?
// w.runANonExistentMethod(); // エラー: オブジェクトの型は 'unknown' です。

if (typeof w === 'object' && w !== null) {
  // if文でのチェックにより、安全にキャスト(Casting)して実行できる
  (w as { runANonExistentMethod: Function }).runANonExistentMethod();
}

2.2 unknown を使用する場面

  • 外部ソース(API、ユーザー入力など)からのデータを扱う場合
  • 柔軟性を維持しつつ、型安全性を確保したい場合
  • JavaScriptからTypeScriptへ型安全な方法で移行する場合

2.3 unknown による型絞り込み(Type narrowing)

型ガード(Type guards)を使用して、unknown 値の型を絞り込むことができます。

function processValue(value: unknown) {
  if (typeof value === 'string') {
    // ここで value は string として扱われる
    console.log(value.toUpperCase());
  } else if (Array.isArray(value)) {
    // ここで value は any[] として扱われる
    console.log(value.length);
  }
}

3. never 型

never 型は、決して発生することのない値の型を表します。
何かが決して起こらない、あるいは起こるべきではないことを示すために使用されます。

3.1 never の一般的なユースケース

  • 決して戻らない関数(常にエラーをスローするか、無限ループに入る関数)
  • タイプチェックを絶対にパスしない型ガード
  • ディスクリミネイテッド・ユニオン(Discriminated unions)における網羅性チェック(Exhaustiveness checking)

3.2 never 型の活用例

1. 値を返さない関数

function throwError(message: string): never {
  throw new Error(message);
}

2. ディスクリミネイテッド・ユニオンによる網羅性チェック

type Shape = Circle | Square | Triangle;

function getArea(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2;
    case 'square':
      return shape.sideLength ** 2;
    default:
      // TypeScriptはここが実行されないことを認識している
      const _exhaustiveCheck: never = shape;
      return _exhaustiveCheck;
  }
}

3. 基本的な never 型(代入時にエラーが発生)

let x: never = true; // エラー: 型 'boolean' を型 'never' に割り当てることはできません。

4. undefined と null

TypeScriptでは、undefinednullstringnumber と同様に、それぞれ独自の型を持っています。
デフォルトでは、これらの型は他の任意の型に代入可能ですが、TypeScriptの厳密なNullチェック(Strict null checks)設定によって挙動が変わります。

4.1 undefined と null のポイント

  • undefined は、変数が宣言されたが値が代入されていないことを意味します。
  • null は、値が存在しない、あるいはオブジェクトが存在しないことを表す明示的な代入です。
  • strictNullChecks が有効な場合、これらの型を明示的に処理する必要があります。

基本的な使用法

let y: undefined = undefined;
let z: null = null;

4.2 オプションパラメータとプロパティ

// オプションパラメータ(暗黙的に `string | undefined` となる)
function greet(name?: string) {
  return `こんにちは、${name || 'ゲスト'}さん`;
}

// インターフェース内のオプションプロパティ
interface User {
  name: string;
  age?: number; // `number | undefined` と同等
}

4.3 Null合体演算子とオプショナルチェイニング

// Null合体演算子 (??) - 値が null または undefined の場合のみデフォルト値を使用
const value = input ?? 'デフォルト値';

// オプショナルチェイニング (?.) - 入れ子になったプロパティに安全にアクセス
const street = user?.address?.street;

       重要: これらの型は、tsconfig.json ファイルで strictNullChecks が有効になっている場合に最も威力を発揮します。これにより、nullundefined がそれ自身および any 型にのみ代入可能であることが保証されます。

厳密なNullチェックを有効にするには、tsconfig.json に以下を追加します。

{
  "compilerOptions": {
    "strictNullChecks": true
  }
}