此实现似乎运行良好(Stackblitz):
/**
* Returns all the elements that are distinct by the
* `property` value. Note that the implementation uses a `Map<string, E>` to
* index the entities by key. Therefore the more recent occurences
* matching a key instance will overwrite the previous ones.
*
* @param property The name of the property to check for distinct values by.
* @param entities The entities in the array.
*
* @example
* ```
* let todos:Todo = [{ id: 1, "Lets do it!" }, {id: 2, "All done!"}];
* let dtodos:Todo[] = distinct<Todo>(todos, 'id');
*/
export function distinct<E>(entities:E[], property:string):E[] {
let map:Map<string, E> = new Map();
entities.forEach((e:E)=>{
map.set(e[property], e);
});
return Array.from(map.values());
}
唯一的问题是VSCode在e[property]
部分下呈波浪状绘制红色,错误消息为:
元素隐式地具有“ any”类型,因为类型“ {}”没有索引签名。ts(7017)
有办法摆脱它吗?
我在此轻量级状态管理器中为对象和实体添加了最新建议的实现:
https://www.npmjs.com/package/@fireflysemantics/slice
npm i @fireflysemantics/slice
...
import {distinct} from '@fireflysemantics/slice/utilities';
答案 0 :(得分:4)
错误消息有点误导。他的问题是,不能像定义e[property]
那样确保string
的类型为Map
。
使any
类型的Map中的键具有很大的灵活性,您也无法确定值的类型。
另外,我将property
参数键入为keyof E
,以便TS确保我只能粘贴该类型的有效属性名称。
function distinct<E>(entities:E[], property:keyof E):E[] {
let map:Map<any, E> = new Map();
entities.forEach((e:E)=>{
map.set(e[property], e);
});
return Array.from(map.values());
}
答案 1 :(得分:2)
基于Thomas'的答案,我们可以简化两者:
"display": "standalone"
; Map
,我们可以转换用作K extends keyof E
构造函数输入参数的元组([E[K], E]
),并删除Map
类型使用。代码在这里:
any
调用function distinct<E, K extends keyof E>(entities: E[], property: K): E[] {
const entitiesByProperty = new Map(entities.map(e => [e[property], e] as [E[K], E]));
return Array.from(entitiesByProperty.values());
}
时,无需指定通用类型,因为可以推断出它们。这是一个工作示例:
distinct()