いくつかの条件をチェックして値を返すか、デフォルトを返す単純な関数の型を正確に表現しようとしています。ほとんどの場合、デフォルトは定数であるため、コール サイトで適切に絞り込まれるように、予期される値とデフォルト値の型の和集合を返すことは理にかなっています。
まず、機能と予想されるユースケース。
const f = (
value: unknown, defaultValue?: string | null | undefined
): string | null | undefined => {
if (typeof value === 'string') {
return value;
}
return defaultValue;
};
const s1: string = f('', 's');
const s2: string | null = f('', null);
const s3: string | undefined = f('', undefined);
const s4: string | undefined = f('');
const x: string | null | undefined = '';
const s5: string | null | undefined = f('', x);
最初の引数の型は常に同じです。実際には識別には影響しません。単純なコード例のために追加されています。出力タイプには常に文字列が含まれます。識別は、呼び出しサイトのデフォルト パラメータのタイプに応じて、出力タイプに null および未定義が含まれる場合にのみ影響します。
指定された関数型では、コンパイラは明らかにケース 1 ~ 4 で文句を言います。
今、識別型を定義するためのさまざまな試み。
interface I {
(value: unknown, defaultValue: string): string;
(value: unknown, defaultValue: null): string | null;
(value: unknown, defaultValue?: undefined): string | undefined;
// (value: unknown, defaultValue?: string | null | undefined): string | null | undefined;
}
type T1 = ((value: unknown, defaultValue: string) => string) |
((value: unknown, defaultValue: null) => string | null) |
((value: unknown, defaultValue?: undefined) => string | undefined) |
((value: unknown, defaultValue: string | null | undefined) => string | null | undefined)
type T2 = <U extends string | null | undefined> (
value: unknown, defaultValue?: U
) => string | U;
オーバーロードを持つインターフェイス I はすべてのユース ケースを満たしますが、f の型と完全に一致する最後のオーバーロードのコメントを外しても、f をそれに割り当てることはできません。また、オーバーロードは冗長です。
f は T1 に割り当て可能ですが、オーバーロードとしては機能しません。
T2 は簡潔で、すべてのユース ケースを満たしますが、それでも f は代入できません。さらに、T2は寛容すぎるconst incorrect: number = f('', <any>1);ため、のような間違った使用例を許可します。extends
上記のインターフェイスと同じオーバーロードを記述する型を作成する方法はありますか? 同じ関数を宣言して、インターフェイスまたは型に割り当て可能にしますか?