[英]Typesafe curried pluck() and pick() in Typescript
我正在嘗試編寫pick()
和pluck()
的類型安全柯里化版本,以便函數首先接收屬性列表,然后接收它們所作用的 object。 我無法弄清楚如何使 output 類型正確。 這是我到目前為止的位置:
export const pick =
<K extends string[], T extends Record<K[number], any>>(...props: K) =>
(obj: T) => {
return props.reduce((result: Partial<T>, nextKey: K[number]) => {
if (nextKey in obj) result[nextKey] = obj[nextKey];
return result;
}, {});
};
export const pluck =
<K extends string[], T extends Record<K[number], any>>(...props: K) =>
(obj: T) =>
props.reduce((result, nextKey: K[number]) => result[nextKey], obj);
pick
很容易定義,因為Pick
已經作為內置實用程序存在:
declare function pick<K extends string[]>(...args: K): <T extends Record<K[number], any>>(obj: T) => Pick<T, K[number]>;
然而, pluck
需要更多的工作,因為我們需要自己制作類型。
給定類似["a", "b", "c"]
東西,我們想要構造一個類型
{ a: { b: { c: any } } }
我們可以使用遞歸類型和Record
簡潔地做到這一點:
type Scoped<K extends string[]> = K extends [infer Head extends string, ...infer Tail extends string[]] ? Record<Head, Scoped<Tail>> : any;
如果沒有輸入(遞歸的基本情況),那么它應該只是any
。
接下來我們需要一個類型來實際進行采摘。 方便的是,由於我們已經有了一個從給定的 props 構造 object 的類型,這個類型也非常緊湊:
type Pluck<T extends Scoped<K>, K extends string[]> = K extends [infer Head extends string, ...infer Tail extends string[]] ? Pluck<T[Head], Tail> : T;
然后可以像這樣在pluck
的定義中使用這些實用程序:
declare function pluck<K extends string[]>(...args: K): <T extends Scoped<K>>(obj: T) => Pluck<T, K>;
這種柯里化方法的一個缺點是您在初次調用時不會獲得任何智能感知……
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.