簡體   English   中英

根據類型保護推斷函數的返回類型

[英]Infer return type of function based on type guard

我有以下定義:

function foo(arg: number[] | number) {
    if (Array.isArray(arg)) {
        return [1]
    }

    return 0
}

我希望打字稿能夠自動找出返回類型是什么。 由於類型保護isArray()它知道 arg 是否是一個數組並且可以將返回類型顯示為number[] 但是,使用foo(...)其返回值顯示為number[] | 0 number[] | 0即使傳遞數組。

  foo([]).push() // error because push doesnt exist on type 0

這是一個設計限制,一個錯誤,還沒有實現,還是其他一些問題?

我不能明確指出這是設計限制,但我見過像jcalzTitian Cernicova-Dragomir這樣的專家引用類型推斷受限的各種地方有時不是因為它不能做我們想要的,而是因為它這樣做成本太高(就運行時成本或編譯器中的代碼復雜性而言)。 我懷疑這屬於那個類別。

您可能知道這一點,但對於您的具體示例,您可以使用重載來獲得所需的結果:

function foo(arg: number[]): number[];
function foo(arg: number): number;
function foo(arg: number[] | number) {
    if (Array.isArray(arg)) {
        return arg.map(v => v * 2);
    }
    
    return arg * 2;
}
foo([]).push(10);

游樂場鏈接

我認為你正在尋找的是重載

如下使用重載將解決您的問題:


function foo(arg1: number[]): number[];
function foo(arg1: number): 0;
function foo(arg1: any){
    if(Array.isArray(arg1)){
        return [0]
    }

    return 0
}

另一種選擇是泛型

function foo<T extends number[] | number>(arg:T):T {
    if (Array.isArray(arg)) { return [1] as T }
    return 0 as T
}

foo([] as number[]).push(10) // works
foo(42).push(10) // error as expected

foo的消費者得到完美的類型。 在內部我們使用類型斷言,因為return ed 值不是sound T的形狀由調用者指定,因此我們無法知道它究竟是什么。

想象一下, 42戀物癖俱樂部擁有foo - 所有其他數字都是 mehh... :)

然后像
function foo<T extends number[] | number>(arg:T):T { if (Array.isArray(arg)) { return [1]} return 1 } foo(42); // T instantiated as 42

顯然是不能容忍的。

雖然這個例子是人為的——盡管俱樂部聽起來很整潔——但你可能明白了為什么第一個例子需要type asserted

更真實的聲音樣本:
 function ensureDefined<T extends number[] | number>(initializer: () => T, arg?: T): T { if (arg === undefined || Array.isArray(arg) && arg.length === 0) { return initializer() } else return arg } ensureDefined(() => [42], [] as number[]).push(10) // works ensureDefined(()=> 42, undefined) // error as expected

這是一個游樂場

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM