関数の型定義があります。次のように、2番目の引数の型を最初の引数の型を条件として定義しています。
const FOO = "FOO";
const BAR = "BAR";
let fooPayload = {
zip: "zap"
}
let barPayload = {
cat: "dog"
}
type ActionTypes = typeof FOO | typeof BAR;
interface MyFunction<T extends ActionTypes = ActionTypes> {
(
action: {
type: T;
payload: T extends typeof FOO
? typeof fooPayload
: typeof barPayload;
}
): boolean;
}
MyFunction
インターフェイスが参照する関数には、に基づいて切り替えaction.type
、場合によってはaction.payload
。を使用して何かを行うswitchステートメントが含まれています。次に例を示します。
const myFunction:MyFunction = (action) => {
switch (action.type) {
case FOO:
action.payload.zip = "new zap"
return true
case BAR:
action.payload.cat = "new dog"
return false
default:
return false
}
}
私が抱えている問題は、Typescriptがaction.payload
switchステートメントから何をすべきかを正しく推測していないことです。たとえば、action.type
が「FOO」に等しい場合、それはでaction.payload
なければならないことを推測する必要がありますtypeof fooPayload
。代わりに、それはであると推測しtypeof fooPayload | typeof barPayload
ます。
の型定義action.payload
はの値に基づいているため、これは意味がありませんaction.type
。また、action.payload.zip
が「FOO」にaction.type
等しい場合にのみ発生する可能性があるswitchステートメント内で呼び出されるため、の唯一の可能な型はであるaction.payload
と推測する必要がありtypeof fooPayload
ます。
私はここで何が間違っているのですか?
これが問題を引き起こしている正確な場所はわかりませんが、一般的に問題は、typescriptがすでにうまく機能している狭い型の共用体を再発明しようとしていることです。
条件文は非常に興味深い機能ですが、分配法則であるため、定義された場所の範囲から外れるため、予期しない動作をすることがあります。
私はこれを別の方法で実装します:
interface Action<T, P> {
type: T,
payload: P
}
type Actions
= Action<typeof FOO, typeof FooPayload>
| Action<typeof BAR, typeof BarPayload>
;
interface MyFunction {
(action: Actions): boolean;
}
条件は必要ありません。typescriptを使用すると、スイッチで期待どおりにユニオンが絞り込まれます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加