我想撰寫一個通用函式,它接受可變數量的引數,這些引數可能具有不同的型別,并根據這些引數回傳一個元組。
以下是 JavaScript 中的示例:
function evaluate (...fns) {
return fns.map(fn => fn())
}
evaluate(
() => 10
) // [ 10 ]
evaluate(
() => 10,
() => 'f',
() => null
) // [ 10, 'f', null ]
在 TypeScript 中,我需要以某種方式將擴展引數元組轉換為結果元組:
function evaluate<T1, T2 ... Tn> (
...fns: [() => T1, () => T2 ... () => Tn]
): [T1, T2 ... Tn] {
return fns.map(fn => fn()) as [T1, T2 ... Tn]
}
evaluate(
() => 10
) // [ 10 ]: [number]
evaluate(
() => 10,
() => 'f',
() => null
) // [ 10, 'f', null ]: [number, string, null]
我嘗試了一種為所有合理長度的元組創建多載的天真的方法:
function evaluate<T1> (
fn1: () => T1
): [T1]
function evaluate<T1, T2> (
fn1: () => T1,
fn2: () => T2
): [T1, T2]
function evaluate<T1, T2, T3> (
fn1: () => T1,
fn2: () => T2,
fn3: () => T3
): [T1, T2, T3]
function evaluate<T1, T2, T3> (
...fns: Array<(() => T1) | (() => T2) | (() => T3)>
): [T1] | [T1, T2] | [T1, T2, T3] {
return fns.map(fn => fn()) as [T1] | [T1, T2] | [T1, T2, T3]
}
但它看起來很糟糕,不能很好地擴展,并且會導致更復雜的函式體出現問題。
有什么辦法可以動態完成嗎?謝謝!
uj5u.com熱心網友回復:
實作這一點的最簡單方法是在其類似陣列的輸出型別(旨在成為元組型別)中創建evaluate()
泛型,然后將其余引數表示為映射型別on ,注意映射的陣列/元組型別也是陣列/元組型別:T
fns
T
function evaluate<T extends any[]>(
...fns: { [I in keyof T]: () => T[I] }
) {
return fns.map(fn => fn()) as T;
}
請注意,型別斷言 as T
是必要的,因為編譯器看不到fns.map(fn => fn())
它將函式型別的陣列/元組轉換為相應回傳型別的陣列/元組的效果。有關更多資訊,請參閱將元組型別的值映射到不同的元組型別的值而不進行強制轉換。
因為{[I in keyof T]: () => T[I]}
是我們直接映射的同態keyof T
映射型別(有關更多資訊,請參閱“同態映射型別”是什么意思?),編譯器能夠從中推斷(T
不推薦使用鏈接頁面,但仍然準確且不存在新頁面???♂?)。
讓我們看看它的實際效果:
const x = evaluate(() => 10);
// const x: [number]
const y = evaluate(
() => 10,
() => 'f',
() => null
)
// const y: [number, string, null]
看起來挺好的。編譯器看到它x
是 type[number]
并且y
是 type [number, string, null]
。在您傳入未知順序/長度的 rest 引數的情況下,它的行為也很合理:
const fs = [() => "a", () => 3];
// const fs: ((() => string) | (() => number))[]
const z = evaluate(...fs);
// const z: (string | number)[]
這里 fs
是 型別Array<(()=>string) | (()=>number)>
,z
類似 型別 也是Array<string | number>
.
Playground 代碼鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/470405.html
標籤:javascript 打字稿 仿制药 类型