2016-04-12 92 views
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; 
} 

基本上,遍历列表并调用用户提供的投影功能,提取地图键和值。

注意,类型TKEY的和TElement从的投影函数的返回值infered在传递

大多数的时候,在地图仅仅是原始的元素:

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,打字稿可以推断,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类型的参数”。

回答

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 */ 

这将是可解与generic type defaults(你会写<T, TKey, TElement = T>),但那些没有被尚未合并。

有关代码的合法投诉,从编译器的角度看,就是有人可能会手动指定所有类型的参数,但不指定可选参数:

let x = toMap<string, number, boolean>(someStringArray, someNumberFunc); 
+0

该申诉是非常合情合理的。当我尝试实现第一个示例(两个签名)时,我遇到了相同类型的错误。我在我的帖子中包含了我的代码。 – Mud