簡體   English   中英

如何將 Typescript 函數重載與具有多個參數的函數一起使用?

[英]How to use Typescript Function Overloading with a function that has multiple parameters?

我有一個函數試圖在數字數組中找到一個值。 該值可以是一個對象或一個數字。 如果值是一個對象,則有一個“key”屬性用於從對象中獲取數字值。

我正在嘗試使用Function Overloading來擁有一個可以處理這兩種情況的函數。

type ObjectType = {
    [key: string]: number
}

type FunctionType = {
    <T extends ObjectType>(v: T, list: number[], key: string): T | undefined
    (v: number, list: number[]): number | undefined
}

const find: FunctionType = <T extends ObjectType | number,>(v: T, list: number[], key?: string)=>{

    const value = typeof v === 'number' ? v : v[key]

    return list.find((item)=>{
        return item === value
    })
}

這會產生錯誤Type undefined cannot be used as an index type

但是在這個分支中,v的值是一個對象,那么key怎么沒有定義呢?

TS-游樂場

謝謝

編輯

Alex Wayne 提出了一個解決方案,但它沒有正確地將值縮小到一個數字。

如果我們不調用 list.find,而是調用一個只接受數字的自定義函數,typescript 會拋出錯誤


const findNumber = (v: number, list: number[])=>{
    /* Do stuff with v as a number */
    return list.indexOf(v)
}

const find: FunctionType = <T extends ObjectType | number>(v: T, list: number[], key?: keyof T)=>{
    const value = (key && typeof v === 'object') ? v[key] : v

    return list[findNumber(value, list)]
}

“ObjectType”類型不能分配給“number”類型

TS-游樂場

實現函數不知道它的重載是什么。 這意味着如果重載函數簽名被刪除,重載函數實現必須仍然完全有效。

因此,雖然如果typeof v === 'number'然后typeof key === 'string'編譯器不知道這一點是正確的。

如果你純粹看這個函數簽名:

<T extends ObjectType | number,>(v: T, list: number[], key?: string)=>{

然后你會看到find({ someKey: 1 }, [1,2,3])是一個有效的調用。 重載阻止了該調用,但該函數在沒有這些重載的情況下也必須有效。


這意味着要解決此問題,您必須在使用之前測試key是否存在。

const value = (key && typeof v === 'number') ? v : v[key]

然而,這又帶來了一個新問題:

Type 'undefined' cannot be used as an index type.(2538)

我相信這是因為typeof v === 'number'不夠細化。 我不確定它認為它可能是什么,但如果你反轉三元並通過typeof v === 'object'打字稿進行優化,那么它會很高興。

const value = (key && typeof v === 'object') ? v[key] : v

操場


最后,您可以在這里使用key: keyof T來提高類型安全性。

const find: FunctionType = <T extends ObjectType | number>(v: T, list: number[], key?: keyof T)=>{
    const value = (key && typeof v === 'object') ? v[key] : v

    return list.find((item)=>{
        return item === value
    })
}

看游樂場

首先,讓我們確保無效狀態是不可表示的。 讓我們定義聯合類型:

type IsObj<T> = {
    value: T, key: keyof T
}

type IsNumber = { value: number }

type Params<T> = IsObj<T> | IsNumber

您可能已經注意到,我綁定了第二個和第三個參數。

現在,我們可以定義我們的自定義類型保護:

const isNumber = <T,>(params: Params<T>): params is IsNumber => typeof params.value === 'number'

讓我們把它放在一起:


type ObjectType = {
    [key: string]: number
}

type IsObj<T> = {
    value: T, key: keyof T
}

type IsNumber = { value: number }

type Params<T> = IsObj<T> | IsNumber

const isNumber = <T,>(params: Params<T>): params is IsNumber => typeof params.value === 'number'

type FunctionType = {
    <T extends ObjectType>(list: number[], params: IsObj<T>): T | undefined
    (list: number[], params: IsNumber): number | undefined
}

const find: FunctionType = <T extends ObjectType | number,>(list: number[], params: Params<T>) => {

    const value = isNumber(params) ? params.value : params.value[params.key]

    return list.find((item) => item === value)
}

const result = find([1, 2, 3], { value: 42}) // ok
const result_ = find([1, 2, 3], { value: { age: 2 }, key: 'age' }) // ok

const result__ = find([1, 2, 3], { value: { age: 2 }, key: 'name' }) // expected error
const result___ = find([1, 2, 3], { value: 42, key: 'name' }) // expected error

操場

暫無
暫無

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

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