【问题标题】:Using a Map instance to return an array of distinct objects by property name?使用 Map 实例按属性名称返回不同对象的数组?
【发布时间】:2019-08-14 12:13:36
【问题描述】:

这个实现似乎运行良好 (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”类型,因为类型“{}”没有索引 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


    【解决方案1】:

    错误消息有点误导。他的问题是,它不能确保 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());
    }
    

    【讨论】:

    • 很好 - 不知道 keyOf 功能 - 谢谢!
    • 使用第二个泛型类型约束K extends keyof E,我们可以摆脱危险的any,将其替换为E[K] - 请参阅我的response
    【解决方案2】:

    基于Thomas'的回答,我们可以简化两者:

    • JavaScript 代码:立即构造Map
    • TypeScript 类型:添加K extends keyof E,我们可以将用作Map 构造函数输入参数的元组([E[K], E])强制转换并删除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 }]
    

    【讨论】:

    猜你喜欢
    • 2015-12-22
    • 1970-01-01
    • 2015-06-21
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    • 1970-01-01
    • 2021-04-19
    • 2015-07-18
    相关资源
    最近更新 更多