2

我写了一个函数来将一个数组投影到一个地图中:

function toMap<T,TKey,TElement>(items: Array<T>,
        keySelector: (item: T) => TKey,
        elementSelector: (item: T) => TElement
    ): Map<TKey,TElement> {

    var map = new Map<TKey,TElement>();
    for (var item of items) {
        map.set(keySelector(item), elementSelector(item));
    }
    return map;
}

基本上,遍历列表并调用用户提供的投影函数来提取 Map 的键和值。

请注意,类型 TKey 和 TElement 是从传入的投影函数的返回值推断出来的。

大多数时候,地图中的只是原始元素:

var personBySocial = toMap(people, person => person.ssn, person => person);

所以我想将第二个 lambda 设为默认值。很简单:

function toMap<T,TKey,TElement>(items: Array<T>,
        keySelector: (item: T) => TKey,
        elementSelector: (item: T) => TElement = item => item
    ): Map<TKey,TElement> {

    var map = new Map<TKey,TElement>();
    for (var item of items) {
        map.set(keySelector(item), elementSelector(item));
    }
    return map;
}

但是,这会产生编译错误:

Type '(item: T) => T' is not assignable to type '(item: T) => TElement'.
  Type 'T' is not assignable to type 'TElement'.

出于某种原因,如果我item => item单独传入,Typescript 可以推断出 TElement == T,但如果我将其作为默认值传入,则不能。

我在这里做错了什么,还是这是 Typescript 当前的限制?如果是后者,有谁知道这是否是将来会解决的已知问题?


编辑,回应瑞安的评论:

function toMap<T,TKey>(items: Array<T>, keySelector: (item: T) => TKey): Map<TKey,T>;
function toMap<T,TKey, TElement>(items: Array<T>, keySelector: (item: T) => TKey, elementSelector: (item: T) => TElement): Map<TKey, TElement>;
function toMap<T,TKey, TElement>(items: Array<T>, keySelector: (item: T) => TKey, elementSelector?: (item: T) => TElement): Map<TKey, TElement> {
    var map = new Map<TKey, TElement>();
    if (elementSelector)
        for (var item of items)
            map.set(keySelector(item), elementSelector(item));
    else
        for (var item of items)
            map.set(keySelector(item), item);
    return map;
}

我遇到了相同类型的错误,其中 else 子句 () 中的 map.set 在map.set(keySelector(item), item)第二个触发错误,item即“T 不可分配给 TElement 类型的参数”。

4

1 回答 1

0

我认为您最好将其写为两个签名:

function toMap<T,TKey>(items: Array<T>, keySelector: (item: T) => TKey): Map<TKey,T>;
function toMap<T,TKey,TElement>(items: Array<T>, keySelector: (item: T) => TKey, elemSelector: (item: T) => TElement): Map<TKey,TElement>;
/* implementation signature here */

这可以通过泛型类型默认值(您可以编写<T, TKey, TElement = T>)来解决,但尚未合并。

从编译器的角度来看,关于您的代码的合理抱怨是有人可能手动指定所有类型参数,但没有指定可选参数:

let x = toMap<string, number, boolean>(someStringArray, someNumberFunc);
于 2016-04-12T22:01:02.620 回答