1. ホーム
  2. typescript

[解決済み] TypeScriptのarrow関数で戻り値の型を指定する

2022-05-06 07:22:26

質問

私はReactとReduxを使用しており、私のリデューサーが型安全性を向上させるためにタグ付きユニオン型を利用できるように、インターフェイスとして指定されたアクションタイプを持っています。

ということで、以下のような型宣言をしています。

interface AddTodoAction {
    type: "ADD_TODO",
    text: string
};

interface DeleteTodoAction {
    type: "DELETE_TODO",
    id: number
}

type TodoAction = AddTodoAction | DeleteTodoAction

これらのアクションを作るヘルパー関数を作りたいのですが、これにはarrow関数を使うことが多いですね。これを書くと

export const addTodo1 = (text: string) => ({
    type: "ADD_TODO",
    text
});

コンパイラは、これが有効な AddTodoAction なぜなら、戻り値の型が明示的に指定されていないからです。このようにすれば、戻り値の型を明示的に指定することができるんだ。

export const addTodo2: (text: string) => AddTodoAction = (text: string) => ({
    type: "ADD_TODO",
    text
})

しかし、これでは関数の引数を2回指定しなければならないので、冗長で読みにくくなってしまいます。

矢印記法を使用する際に、戻り値の型を明示的に指定する方法はありますか?

試してみようと思ったことがあります。

export const addTodo3 = (text: string) => <AddTodoAction>({
    type: "ADD_TODO",
    text
})

この場合、コンパイラは戻り値の型を次のように推測します。 AddTodoAction しかし、返そうとするオブジェクトが適切なフィールドをすべて持っているかどうかは検証されない。

別の関数の構文に変えれば解決するんだけど。

export const addTodo4 = function(text: string): AddTodoAction {
    return {
        type: "ADD_TODO",
        text
    }
}

export function addTodo5(text: string): AddTodoAction {
    return {
        type: "ADD_TODO",
        text
    }
}

これらのメソッドは、コンパイラが正しい戻り値の型を使用し、すべてのフィールドを適切に設定したことを強制します。 this は関数内で処理されます(これは問題ではないかもしれませんが。)

何か良い方法はないでしょうか?

どのように解決するのですか?

まず、最初の質問で出てきた以下の表記を考えてみましょう。

export const addTodo3 = (text: string) => <AddTodoAction>({
    type: "ADD_TODO",
    text
})

この記法を用いて、返されたオブジェクトをタイプキャストして、タイプ AddTodoAction . しかし,この関数が宣言している戻り値の型はまだ未定義です(コンパイラは暗黙のうちに any を返り値として使用します)。

代わりに以下の表記を使用します。

export const addTodo3 = (text: string): AddTodoAction => ({
    type: "ADD_TODO",
    text: text
})

この場合、必須のプロパティを省略すると、期待通りのコンパイラーエラーが発生します。例えば text プロパティは、次のような(望ましい)エラーを発生させます。

Type '{ type: "ADD_TODO"; }' is not assignable to type 'TodoAction'.
  Type '{ type: "ADD_TODO"; }' is not assignable to type 'DeleteTodoAction'.
    Types of property 'type' are incompatible.
      Type '"ADD_TODO"' is not assignable to type '"DELETE_TODO"'.

また プレイグラウンドの例 .