Typescript:映射键的类型与值的类型相同,但不限制键的类型

Typescript:映射键的类型与值的类型相同,但不限制键的类型,typescript,dictionary,generics,Typescript,Dictionary,Generics,有没有办法进行以下的打字检查 const map = new Map() map.set('stringkey', 'stringvalue') // OK map.set(5, 10) // OK const objectKey = { name: 'bob' } map.set(objectKey, { name: 'alice' }) // OK const stringValue: string = map.get('stringkey') // OK, but is typed a

有没有办法进行以下的打字检查

const map = new Map()

map.set('stringkey', 'stringvalue') // OK
map.set(5, 10) // OK
const objectKey = { name: 'bob' }
map.set(objectKey, { name: 'alice' }) // OK

const stringValue: string = map.get('stringkey') // OK, but is typed as 'any'
const objectValue: { name: string } = map.get(objectKey) // OK, but is typed as 'any'

map.set('string', 5) // Error
map.set({ name: 'bob' }, { food: 'cake' }) // Error
使用默认值

const map = new Map<any, any>()
const map=new map()

可以工作,但在访问值时不会提供有用的类型,因为它们都是按任何类型键入的。

这很有趣。我认为最好的方法是声明您自己的接口,它代表您的
映射的特定变体

interface SameKeyValueMap {
  clear(): void;
  delete(key: any): boolean;
  forEach(
    callbackfn: <T>(value: T, key: T, map: SameKeyValueMap) => void, thisArg?: any
  ): void;
  get<T>(key: T): T | undefined;
  has(key: any): boolean;
  set<T>(key: T, value: T): this;
  readonly size: number;
}

const map: SameKeyValueMap = new Map();
必须更改以下内容,因为
get()
可以返回
未定义的

const stringValue: string | undefined = map.get('stringkey')
const objectValue: { name: string } | undefined = map.get(objectKey)
下面是您想要的错误:

map.forEach((x, y) => (console.log(x === y))); // OK
map.set('stringkey', 'stringvalue') // OK
map.set(5, 10) // OK
const objectKey = { name: 'bob' }
map.set(objectKey, { name: 'alice' }) // OK
map.set('string', 5) // Error
但以下不是错误:

map.set({ name: 'bob' }, { food: 'cake' }) // accepted?
如果你看,那是因为类型
T
被推断为
{name:string,food?:undefined}{name?:undefined,food:string}
。这与您传入的值是一致的。那样的话,类型推断有点像黑色艺术

解决这个问题的一种方法是将
T
的一个推理站点的
set()
签名更改为。这样一来,
T
将仅从其中一个参数推断,而不是同时从两个参数推断。像这样:

interface SameKeyValueMap {
  clear(): void;
  delete(key: any): boolean;
  forEach(
    callbackfn: <T>(value: T, key: T, map: SameKeyValueMap) => void, thisArg?: any
  ): void;
  get<T>(key: T): T | undefined;
  has(key: any): boolean;
  set<T>(key: T, value: T & {}): this; // lowered priority of value
  readonly size: number;
}
在这种情况下,
T
被推断为
{name:string}
{food:'cake'}
不可分配给它。所以这是一个错误



希望有帮助。祝你好运

虽然现代JS实现了一个可以接受对象作为键的映射,但它的行为可能并不像您期望的那样。如果键不是字符串或数字,则按标识(而不是值)比较键。换句话说,键将与
==
操作符进行比较,具有相同键和值的两个对象不一定相互
==
map.set({ name: 'bob' }, { food: 'cake' }) // error