Skip to content

Instantly share code, notes, and snippets.

@LeeDDHH
Last active January 21, 2022 00:23
Show Gist options
  • Save LeeDDHH/9fcd626a7c594849302b335327169be8 to your computer and use it in GitHub Desktop.
Save LeeDDHH/9fcd626a7c594849302b335327169be8 to your computer and use it in GitHub Desktop.
typescriptのタイプ指定でわかったことについてのあれこれ

メンバー間に共通点がないタイプをUnion型にして、特定のメンバーを分岐条件に使う

前提

たとえば、以下のようにそれぞれのメンバーが異なるタイプの定義があるとする
そして、そのメンバーを1つのUnion型として扱うケースがあるとする

type SaveFilePath = { saveFilePath: string };
type PrefixName = { prefixName: string };
type ShortCut = { shortCut: string[] };
type LogFlag = { logFlag: boolean };
type Count = { count: number };

type OneOfModifiedData = SaveFilePath | PrefixName | ShortCut | LogFlag | Count;

データを扱う関数ではUnion型を引数のtypeにして、関数内ではそのデータを他の関数へ受け渡す役割を持っているとする

const someFunction = (data: OneOfModifiedData): void => {
  deliverFunction(data);
  deliverOtherFUnction(data);
}

処理の追加

ここで、とあるtypeでのみ行う予定の処理を追加するケースが発生したとする

const someFunction = (data: OneOfModifiedData): void => {
  deliverFunction(data);
  // 追加
  if (data.prefixName) {
    putSomeFunction(data);
  }
  // 追加end
  deliverOtherFUnction(data);
}

ただ、Union型で指定した場合は複数の型のすべてに共通するメンバーのみが参照/呼び出しの対象となる
そのため、Union型として指定した複数の型に共通するメンバーを使用しないと、以下のような文章で注意文が表示される

プロパティ 'prefixName' は型 'SaveFilePath' にありませんが、型 'PrefixName' では必須です

では、どうすればUnion型で指定した複数の型のうち、特定の型でデータが渡された時の判定ができるのか

型の保護と型の識別(Type Guards and Differentiating Types)を使用して実装をする

特定の型のデータが渡ってくることを明示的に型注釈(type assertion)を指定すればいい

const someFunction = (data: OneOfModifiedData): void => {
  deliverFunction(data);
  // 型注釈(type assertion)
  if ((<PrefixName>data>.prefixName) {
    putSomeFunction(data);
  }
  deliverOtherFUnction(data);
}

高等な型 | TypeScript 日本語ハンドブック | js STUDIO


コールバック引数として使う関数に型をつける

前提

VSCodeで引数にコールバック関数を設定して、型として Function をつけると typescript-eslint で以下のように怒られる

Don't use `Function` as a type. The `Function` type accepts any function-like value.
It provides no type safety when calling the function, which can be a common source of bugs.
It also accepts things like class declarations, which will throw at runtime as they will not be called with `new`.
If you are expecting the function to accept certain arguments, you should explicitly define the function shape.

解決策としては2つある

引数に固定の型を指定する

voidを返す無名関数をコールバック引数として使う場合、以下のように書ける

// 無名関数の型定義
declare type NoNameFUnctionReturnVoid = () => void;

// 関数の定義
const somefunction = (callback: NoNameFunctionReturnVoid) => {
  
  callback();
};

// 実行時
somefunction(() => {...なんかの処理...});

TypeScriptで関数を型にする - Qiita

引数にジェネリックの型を指定する

上記と同じく、voidを返す無名関数をコールバック引数として使う場合、以下のように書ける

// 無名関数の型定義
declare type NoNameFUnctionReturnVoid = () => void;

// 関数の定義
const somefunction = <T>(callback: T) => {
  
  callback();
};

// 実行時
somefunction<NoNameFUnctionReturnVoid>(() => {...なんかの処理...});

クラスのstaticな値にインデックスシグニチャーで参照する

  • クラス内に以下を追加
static [key: string]: any
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment