打字稿求和类型

时间:2019-07-12 18:21:07

标签: typescript functional-programming

我正在尝试实现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]是数字属性。我肯定在这里做错了。

2 个答案:

答案 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的第二个参数进行反映射。

请注意,您可以同时使用contramappublic 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; } 等进行循环融合。