这是我能想象得到的最接近的,虽然我仍然不明白为什么我们不只使用普通对象开始:
type ObjectToEntries<O extends object> = { [K in keyof O]: [K, O[K]] }[keyof O]
interface ObjectMap<O extends object> {
forEach(callbackfn: <K extends keyof O>(
value: O[K], key: K, map: ObjectMap<O>
) => void, thisArg?: any): void;
get<K extends keyof O>(key: K): O[K];
set<K extends keyof O>(key: K, value: O[K]): this;
readonly size: number;
[Symbol.iterator](): IterableIterator<ObjectToEntries<O>>;
entries(): IterableIterator<ObjectToEntries<O>>;
keys(): IterableIterator<keyof O>;
values(): IterableIterator<O[keyof O]>;
readonly [Symbol.toStringTag]: string;
}
interface ObjectMapConstructor {
new <E extends Array<[K, any]>, K extends keyof any>(
entries: E
): ObjectMap<{ [P in E[0][0]]: Extract<E[number], [P, any]>[1] }>;
new <T>(): ObjectMap<Partial<T>>;
readonly prototype: ObjectMap<any>;
}
const ObjectMap = Map as ObjectMapConstructor;
这个想法是创建一个新的接口,ObjectMap
它具体依赖于对象类型O
来确定其键/值关系。然后你可以说Map
构造函数可以充当ObjectMap
构造函数。我还删除了任何可以更改实际存在哪些键的方法(并且该has()
方法也是冗余的true
)。
我可以通过解释每个方法和属性定义的麻烦,但这是很多类型的杂耍。简而言之,您想使用K extends keyof O
andO[K]
来表示通常由K
和V
in表示的类型Map<K, V>
。
构造函数有点烦人,因为类型推断不能按照您想要的方式工作,因此保证类型安全分为两个步骤:
// let the compiler infer the type returned by the constructor
const myMapInferredType = new ObjectMap([
['key1', 'v'],
['key2', 1],
]);
// make sure it's assignable to `ObjectMap<Values>`:
const myMap: ObjectMap<Values> = myMapInferredType;
If your myMapInferredType
doesn't match ObjectMap<Values>
(e.g., you are missing keys or have the wrong value types) then myMap
will give you errors.
Now you can use myMap
as an ObjectMap<Values>
, similarly to how you'd use a Map
instance, with get()
and set()
, and it should be type safe.
Please note again... this seems like a lot of work for a more complex object with trickier typings and no more functionality than a plain object. I would seriously warn anyone using a Map
whose keys are subtypes of keyof any
(that is, string | number | symbol
) to strongly consider using a plain object instead, and be sure that your use case really necessitates a Map
.
Playground link to code