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