我编写了一个将数组投影到Map中的函数:
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(keySelector(item), item)
)中的map.set触发了第二个item
上的错误“T不能分配给参数输入TElement“。
答案 0 :(得分: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);