[英]Function that accepts only keys of array values (and deduces return type)
我正在嘗試在typescript 2.8中修改新的條件類型 。
例如,我有一些具有數組屬性的對象,在我的流程中必須只有一個元素,我想得到這個值。 這是我認為應該工作的代碼 ,它正確地只允許傳遞相關的屬性,但我無法弄清楚如何指定返回類型。 我收到以下編譯錯誤:
類型
number
不能用於索引類型Pick<T, { [K in keyof T]: T[K] extends any[] ? K : never; }[keyof T]>[K]
Pick<T, { [K in keyof T]: T[K] extends any[] ? K : never; }[keyof T]>[K]
Pick<T, { [K in keyof T]: T[K] extends any[] ? K : never; }[keyof T]>[K]
。
並且n
和s
的類型被推導為number|string
而不是n
number
和s
string
。
代碼如下:
type ArrayProperties<T> = Pick<T, {
[K in keyof T]: T[K] extends Array<any>? K : never
}[keyof T]>;
const obj = {
a: 4,
n: [2],
s: ["plonk"]
};
// Compilation error on next line
function single<T, K extends keyof ArrayProperties<T>>(t: T, k: K): ArrayProperties<T>[K][number] {
const val = t[k];
if (!Array.isArray(val))
throw new Error(`Expected ${k} to be an array`);
if (val.length !== 1)
throw new Error(`Expected exactly one ${k}`);
return val[0];
}
const n = single(obj, "n"); // 'n' should be of type 'number'
const s = single(obj, "s"); // 's' should be of type 'string'
const a = single(obj, "a"); // Should fail to compile (OK)
您可以使用一些變通方法來實現此功能。
要強制TypeScript編譯器在無法驗證屬性存在時查找屬性,可以將鍵類型與已知鍵相交。 像這樣:
type ForceLookup<T, K> = T[K & keyof T]; // no error
所以你可以改變
ArrayProperties<T>[K][number]
至
ForceLookup<ArrayProperties<T>[K],number>
讓我們確保它有效:
type N = ForceLookup<ArrayProperties<typeof obj>["n"],number>; // number ✔️
type S = ForceLookup<ArrayProperties<typeof obj>["s"],number>; // string ✔️
n
和s
較窄類型: 問題是K
沒有被推斷為字符串文字。 要提示編譯器應盡可能為類型參數推斷字符串文字,可以添加約束extends string
。 它沒有詳細記錄,但有些特殊情況下TypeScript推斷文字類型而不是擴展到更一般的類型(所以當1
被推斷為1
而不是number
,或當'a'
被推斷為'a'
不是string
)。 keyof ArrayProperties<T>
顯然不會觸發此非擴展,因此在所有情況下K
都擴展為keyof ArrayProperties<T>
。 以下是K
的解決方法:
K extends string & keyof ArrayProperties<T>
讓我們看看這一切:
declare function single<T, K extends string & keyof ArrayProperties<T>>(
t: T, k: K): ForceLookup<ArrayProperties<T>[K],number>;
const n = single(obj, "n"); // number ✔️
const s = single(obj, "s"); // string ✔️
const a = single(obj, "a"); // still error ✔️
全部完成!
好吧,我會在這里做一些簡化。 對於您實際可以使用的任何K
, ArrayProperties<T>[K]
可以減少到T[K]
。 所以你得到:
declare function single<T, K extends string & keyof ArrayProperties<T>>(
t: T, k: K): ForceLookup<T[K],number>;
現在一切都是真的。
希望有所幫助。 祝好運!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.