ウェブサイト検索

TypeScript: 関数式のオーバーロード


私は関数宣言でオーバーロードを使用するこのTypeScriptコードを持っています。このコードは期待どおりに動作します。

function identity(x: string): string;
function identity(x: number): number;
function identity(x: string | number): string | number {
    return x;
}

const a = identity('foo') // string
const b = identity(1) // number
const c = identity({}) // type error (expected)

私は関数宣言の代わりに関数式を使用してこれと同等のことを達成しようとしていますが、型エラーが出ます:

/* Type '(x: string | number) => string | number' is not assignable to type '{ (x: string): string; (x: number): number; }'.
    Type 'string | number' is not assignable to type 'string'.
        Type 'number' is not assignable to type 'string' */
const identity: {
    (x: string): string;
    (x: number): number;
} = (x: string | number): string | number => x;

関数式で関数のオーバーロードと同じ効果をどのように達成できるか知りたいです。

回答 #1

代わりに関数の実装に型アサーションを使用することができます。代入では互換性のチェックがより厳しく、アサーションを使うとそれは緩やかになります。それにもかかわらず、私たちは依然としてかなりの量の型安全性を得ることができます(オーバーロードから実装署名へのチェックと同等かどうかは確かではありませんが、かなり近いように思えます):

//OK
const identity = ((x: string | number): string | number => x) as {
    (x: string): string;
    (x: number): number;
};

// Error argument is incompatible
const identity2 = ((x: boolean): string | number => x) as {
    (x: string): string;
    (x: number): number;
};

// Error return type is incompatible 
const identity3 = ((x: string | number) => false) as {
    (x: string): string;
    (x: number): number;
};