这个实现似乎工作正常(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]
部分下绘制一个红色波浪形,错误信息是:
元素隐式具有“任意”类型,因为类型“{}”没有索引signature.ts(7017)
有没有办法摆脱它?
我为这个轻量级状态管理器添加了最新的建议实现,用于对象和实体:
https://www.npmjs.com/package/@fireflysemantics/slice
npm i @fireflysemantics/slice
...
import {distinct} from '@fireflysemantics/slice/utilities';
错误消息有点误导。他的问题是,它无法确保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());
}
根据Thomas的回答,我们可以简化两者:
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()
时,不需要指定泛型类型,因为它们可以被推断。这是一个有效的例子:
enum Status { Pending = 0, Done = 1 }
interface Todo { id: number, label: string, status: Status, date?: Date }
const todos: Todo[] = [
{ id: 1, label: 'Task 1', status: Status.Pending },
{ id: 2, label: 'Task 2', status: Status.Pending },
{ id: 1, label: 'Task 1', status: Status.Done },
];
distinct(todos, 'id'); // [{ id: 1, ... status: 1 }, { id: 2, ... status: 0 }]