使用Map实例按属性名称返回不同对象的数组?

问题描述 投票:2回答:2

这个实现似乎工作正常(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';

演示

https://stackblitz.com/edit/typescript-slice-distinct

javascript node.js typescript slice
2个回答
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());
}

2
投票

根据Thomas的回答,我们可以简化两者:

  • JavaScript代码:立刻构建Map;
  • TypeScript输入:添加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 }]
© www.soinside.com 2019 - 2024. All rights reserved.