鑒于:
class Foo {}
class Bar {}
interface QueryResult<T> {
data: T;
}
function creatQueryResult<T>(data: T): QueryResult<T> {
return {data};
}
function tuple<T extends any[]>(...args: T): T {
return args;
}
我想使用接受的推斷型別QueryResult[]或QueryResults 的元組以及選擇data和呼叫回呼的工廠回呼來創建和鍵入函式,例如:
function createCompoundResult<T>(
queryResults: T,
callback: (queryResultDatas: ???<T>) => any
) {
const datas = queryResults.map((queryResult) => queryResult.data);
return callback(datas);
}
注意???上面代碼中的。
用法:
const fooQueryResult = creatQueryResult(new Foo());
const barQueryResult = creatQueryResult(new Bar());
// Maybe using tuples are wrong?
const queryResults = tuple(fooQueryResult, barQueryResult);
createCompoundResult(
queryResults,
(datas) => {
const [foo, bar] = datas;
// foo should be inferred as Foo here and bar as Bar
}
);
也許元組是錯誤的方法?你會怎么解決?
我是一個 TypeScript 新手,我很難理解 , 之類的東西,keyof所以如果你的解決方案包括像這樣的奧術魔法,請像我 5 歲一樣向我解釋。extends keyof{ [K in keyof T]: { a: T[K] } }
uj5u.com熱心網友回復:
我的建議createCompoundResult()是這樣的:
function createCompoundResult<T extends any[]>(
queryResults: readonly [...{ [I in keyof T]: QueryResult<T[I]> }],
callback: (queryResultDatas: readonly [...T]) => any
) {
const datas = queryResults.map((queryResult) => queryResult.data) as T;
return callback(datas);
}
該函式在 中是通用的T,對應于 的引數元組callback。為了queryResults根據陣列/元組型別來描述 的型別T,我們希望將其映射到另一個陣列/元組型別,其中對于 的每個數字索引I,T元素型別T[I]都映射到QueryResult<T[I]>。所以如果T是[string, number],那么我們想queryResults成為型別[QueryResult<string>, QueryResult<number>]。
您可以通過映射型別來做到這一點。它看起來像{ [I in keyof T]: QueryResult<T[I]> }。對于類似陣列的泛型型別T,映射型別[I in keyof T]只遍歷類似數字的鍵I(并跳過所有其他陣列鍵,如"push"and "length")。所以你可以想象 { [I in keyof T]: QueryResult<T[I]> }對be和 then 、and is和is 進行T操作[string, boolean],所以你得到了,它被神奇地解釋為一種新的元組型別。I"0""1"T["0"]stringT["1"]boolean{0: QueryResult<string>, 1: QueryResults<boolean>} [QueryResult<string>, QueryResult<boolean>]
這是主要的解釋,盡管有一些突出的事情要提。
首先是編譯器不知道陣列map()方法會把一個元組變成一個元組,它肯定不知道queryResult => queryResult.data會把一個型別{ [I in keyof T]: QueryResult<T[I]> }的元組變成一個型別的元組T。(有關更多資訊,請參閱此問題。)它將您的queryResults.map(...)行的輸出型別視為T[number][],意思是:某些元素型別的陣列T。它丟失了長度和順序資訊。所以我們必須使用型別斷言來告訴編譯器 的輸出queryResults.map(...)是型別的T,這樣datas就可以傳遞給callback.
接下來,有幾個地方我AAA在readonly [...AAA]. 這使用可變元組型別語法給編譯器一個提示,我們希望它推斷元組型別而不是陣列型別。如果您不使用它,那么類似的東西[fooQueryResult, barQueryResult]往往會被推斷為陣列型別Array<QueryResult<Foo> | QueryResult<Bar>>而不是所需的元組型別[QueryResult<Foo>, QueryResult<Bar>]。使用這種語法使我們無需使用tuple()輔助函式,至少在直接傳遞陣列字面量的情況下是這樣。
無論如何,讓我們確保它有效:
class Foo { x = 1 }
class Bar { y = 2 }
createCompoundResult(
[fooQueryResult, barQueryResult],
(datas) => {
const [foo, bar] = datas;
foo.x
bar.y
}
);
Looks good. I gave some structure to Foo and Bar (it's always recommended to do so even for example code) and sure enough, the compiler understands that datas is a tuple whose first element is a Foo and whose second element is a Bar.
Playground link to code
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/437844.html
標籤:javascript 打字稿 仿制药 元组
