😽

[typescript]Unionタイプを使う時の注意点と解決方法

2024/12/17に公開

1. ユニオン型使用のよくあるミス

以下のような状況において、通常ユニオン型を適用してしまうことがあります。

パラメータの型に柔軟性を持たせたい場合

type Person = {
  name: string;
  age: number;
};

type Staff = {
  name: string;
  department: string;
};

function introduce(someone: Person | Staff) {
  someone.name;
  someone.age; // エラーが発生
  someone.department; // エラーが発生
}

戻り値の型を柔軟にしたい場合

function add(a: string | number, b: string | number): string | number {
  return a + b; // エラーが発生
}

const result: string | number = add(1, 2);
result.charAt(1); // エラーが発生

2. ユニオン型使用時に発生するエラー

TypeScriptでは、パラメータの型をユニオン型で設定する場合、全ての可能な型に対して安全に動作させることを保証しようとします。この結果、AとBの型に共通して存在するプロパティのみがアクセス可能となります。

function introduce(someone: Person | Staff) {
  someone.name;
  someone.age; // エラーが発生
  someone.department; // エラーが発生
}

上記の例では、Person と Staff という2つの型に共通しているプロパティである name だけがアクセス可能です。age や department は共通プロパティではないため、エラーが発生します。

function add(a: string | number, b: string | number): string | number {
  return a + b; // エラーが発生
}
const result: string | number = add(1, 2);
result.charAt(1); // エラーが発生

この関数の戻り値の場合でも同様です。TypeScriptは静的型検査器であるため、関数が返す値の正確な型を予測することはできません。そのため、result.charAt(1) のような呼び出しでは、戻り値が number である場合に charAt メソッドを使用できないため、型エラーが発生します。

3. 解決方法

関数のオーバーロードを使用して、各状況に対してより明確な戻り値の型を定義することができます。これにより、特定の型の引数を受け取るときに戻り値の型を明確にするので、コンパイラが警告を発生させないようにできます。

function add(x: number, y: number): number;
function add(x: string, y: string): string;
function add(x: any, y: any): any {
    return x + y;
}

関数で any 型を使用しても問題ないか?

コンパイラはオーバーロード関数の宣言部の型のみをチェックするため、オーバーロード関数内での any 型は許容されると考えられます。

参考文献: TypeScriptでの関数文法の総まとめ - Inpa Dev 👨‍💻

Discussion