如何在TypeScript的Map中使用自定义类对象作为键
原生Map默认采用SameValueZero算法做键匹配,对象类型的键只会匹配引用地址,无法直接指定按属性值匹配,你可以通过两种方案实现需求:
方案1:调整存储结构(简单易上手,无需额外封装)
直接将Map的键设为name字符串类型,值同时保存Foo实例和业务数据,既能通过name快速查询,也能保留完整的实例属性:
class Foo { name: string; data1: any; data2: any; } // 定义Map值的类型,同时关联Foo实例和业务数据 type MapValue<DataType> = { fooInstance: Foo; businessData: DataType; } // 声明Map,键为name字符串类型 const map = new Map<string, MapValue<unknown>>(); // 写入数据 const fooObject1 = new Foo(); fooObject1.name = "nameOfFooObject"; map.set(fooObject1.name, { fooInstance: fooObject1, businessData: someData }); // 读取数据 const target = map.get("nameOfFooObject"); if (target) { // 可直接访问Foo实例的data1、data2属性 console.log(target.fooInstance.data1, target.businessData); }
方案2:封装自定义Map类(兼容原生Map用法,适合高频使用场景)
如果希望保留你示例中set传Foo实例、get传name字符串的调用方式,可以继承原生Map重写核心方法,内部自动提取name作为实际匹配键:
class FooMap<DataType> extends Map<Foo | string, DataType> { // 内部存储映射:name -> [Foo实例, 业务数据] #innerStore = new Map<string, [Foo, DataType]>(); override get(key: Foo | string): DataType | undefined { const realKey = typeof key === "string" ? key : key.name; return this.#innerStore.get(realKey)?.[1]; } override set(key: Foo, value: DataType): this { this.#innerStore.set(key.name, [key, value]); return this; } override has(key: Foo | string): boolean { const realKey = typeof key === "string" ? key : key.name; return this.#innerStore.has(realKey); } override delete(key: Foo | string): boolean { const realKey = typeof key === "string" ? key : key.name; return this.#innerStore.delete(realKey); } // 额外工具方法:直接通过name获取完整Foo实例 getInstanceByName(name: string): Foo | undefined { return this.#innerStore.get(name)?.[0]; } } // 用法和你的示例完全一致 const map = new FooMap<unknown>(); map.set(fooObject1, someData); map.set(fooObject2, someData); // 直接传name字符串取值 map.get("nameOfFooObject"); // 也可以传Foo实例取值 map.get(fooObject1); // 直接获取Foo实例访问data属性 map.getInstanceByName("nameOfFooObject")?.data2;
注意:两种方案都默认Foo的
name属性是唯一的,如果存在重名情况,需要自己添加写入校验逻辑,避免数据被覆盖。
内容的提问来源于stack exchange,提问作者HelloWorld
相关产品推荐
相关产品推荐

