簡體   English   中英

僅接受數組值鍵的函數(並推導返回類型)

[英]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]

並且ns的類型被推導為number|string而不是n numbers 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 ✔️

推斷ns較窄類型:

問題是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 ✔️

全部完成!


好吧,我會在這里做一些簡化。 對於您實際可以使用的任何KArrayProperties<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.

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