我正在尝试实现sumPluck函数。它将允许调用者在数组中指定属于对象的数字类型的属性,然后对其求和。
示例:
type A = { prop: number }
const arr: A[] = [{prop: 1}, {prop: 2}];
pluckSum("prop", arr); // 3
我知道如何键入摘录,但是我似乎无法让我的类型认识到它实际上只是在处理数字属性。这就是我所拥有的:
type PropertiesOfTypeNames<T, U> = { [K in keyof T]: T[K] extends U ? K : never }[keyof T];
type PropertiesOfType<T, U> = Pick<T, PropertiesOfTypeNames<T, U>>;
type NumberProperties<T> = PropertiesOfType<T, number>;
const pluckSum = <T, K extends keyof NumberProperties<T>>(arr: T[], k: K) =>
pipe(
arr,
R.map(v => v[k]),
R.sum
);
我在地图下看到一条错误消息:类型'T [string]'不能分配给类型'数字
因此,似乎映射类型并没有传达v [k]是数字属性。我肯定在这里做错了。
答案 0 :(得分:2)
弄清楚了。我只需要这样添加Record:
const pluckSum = <T extends Record<K, number>, K extends keyof NumberProperties<T>>(arr: T[], k: K) =>
pipe(
arr,
R.map(v => v[k]),
R.sum
);
更新1 我想我可以通过删除映射的类型“ NumberProperties”来进一步完善它,因为Record会照料我一直试图实现的目标。所以最终版本是:
const pluckSum = <T extends Record<K, number>, K extends keyof T>(k: K, arr: T[]) =>
pipe(
arr,
R.map(v => v[k]),
R.sum
);
答案 1 :(得分:2)
不管打字稿是什么,我都想向您展示使用循环融合的另一种方法,即消除冗余数组遍历。我使用(b -> c) -> (a -> c -> d) -> a -> b -> d
类型({Hindley-Milner表示)的contramap2nd
类型的非传统组合器进行循环融合,之所以称为// (b -> c) -> (a -> c -> d) -> a -> b -> d
const contramap2nd = g => f => x => y =>
f(x) (g(y));
const arrFold = f => init => xs =>
xs.reduce((acc, x) => f(acc) (x), init);
const add = x => y => x + y;
const prop = k => o => o[k];
const pluckSum = k =>
arrFold(
contramap2nd(
prop(k))
(add)) (0);
console.log(
pluckSum("foo") ([{foo: 1}, {foo: 2}, {foo: 3}]));
,是因为它与二进制函数的第二个参数相反。
长话短说:
add
当然,如果您不喜欢contramap2nd
,则可以手动对map
的第二个参数进行反映射。
请注意,您可以同时使用contramap
和public static string GetDayName(this DateTime date)
{
string _ret = string.Empty; //Only for .NET Framework 4.0++
var culture = new System.Globalization.CultureInfo("en-US"); //<- 'es-419' = Spanish (Latin America), 'en-US' = English (United States)
_ret = culture.DateTimeFormat.GetDayName(date.DayOfWeek); //<- Get the Name
_ret = culture.TextInfo.ToTitleCase(_ret.ToLower()); //<- Convert to Capital title
return _ret;
}
等进行循环融合。