Вот самое близкое, что я могу себе представить, хотя я все еще не понимаю, почему мы не просто используем простые объекты для начала:
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] }>;
readonly prototype: ObjectMap<any>;
}
const ObjectMap = Map as ObjectMapConstructor;
Идея состоит в том, чтобы создать новый интерфейс, ObjectMap
, который конкретно зависит от типа объекта O
для определения его отношения ключ / значение.И тогда вы можете сказать, что конструктор Map
может действовать как конструктор ObjectMap
.Я также удалил все методы, которые могут изменить, какие ключи на самом деле присутствуют (и метод has()
также избыточно true
).
Я могу разобраться с каждым методом и определением свойства, но этомного жонглирования.Короче говоря, вы хотите использовать K extends keyof O
и O[K]
для представления типов, обычно представляемых K
и V
в 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;
Если ваш myMapInferredType
не соответствует ObjectMap<Values>
(например, вам не хватает ключей или неправильных типов значений), тогда myMap
выдаст вам ошибки.
Теперь вы можете использовать myMap
как ObjectMap<Values>
,аналогично тому, как вы используете Map
экземпляр с get()
и set()
, и он должен быть безопасным для типа.
Пожалуйста, обратите внимание еще раз ... это похоже на большую работу дляболее сложный объект с более сложными типами и не более функциональными, чем простой объект.Я бы серьезно предупредил любого, кто использует Map
, чьи ключи являются подтипами keyof any
(то есть string | number | symbol
), чтобы настоятельно рассмотреть возможность использования простого объекта вместо этого, и был бы уверен, что ваш вариант использования действительно требуетMap
.
Хорошо, надеюсь, это поможет вам.Удачи!