TypeScript 无法正确推断对象的类型 属性
TypeScript Does not Properly Infer the Type of an Object's Property
我正在尝试创建一个对象,其中每个 属性 都映射到一个 class 实例。 class 类型依赖于两个泛型。当我在我的对象中访问 属性 时,TypeScript 将 属性 的类型推断为用于定义对象的联合类型,而不是 属性 本身的类型。
如何让 TypeScript 正确推断 属性 的类型?
这里有一段代码可以帮助澄清问题:
export class CacheWithExpiry<T extends CacheTypes, V extends CacheNames> {
constructor() {
}
...
}
export type CacheNames =
'foo_1' |
'foo_2'
type CacheTypes = string | number
type CacheMap<T extends CacheTypes, V extends CacheNames> = { [key: string]: CacheWithExpiry<T, V> }
export const cacheMap: CacheMap<CacheTypes, CacheNames> = {
foo1Cache: new CacheWithExpiry<string, 'foo_1'>(), // Type is inferred as expected 'CacheWithExpiry<string, "foo_1">'
foo2Cache: new CacheWithExpiry<number, 'foo_2'>()
} as const
cacheMap.foo1Cache// Type is inferred as 'CacheWithExpiry<CacheTypes, CacheNames>' instead of 'CacheWithExpiry<string, "foo_1">'
编辑 1:我还需要维护 cacheMap
的类型安全,因此从 cacheMap
中完全删除类型是行不通的。示例:
export const cacheMap = {
foo1Cache: new CacheWithExpiry<string, 'foo_1'>(),
foo2Cache: new CacheWithExpiry<number, 'foo_2'>(),
foo3: 'I am not a cache class instance', // I still want this to throw an error
} as const
您已将类型 CacheMap<CacheTypes, CacheNames>
分配给变量 cacheMap
。此类型不包含有关键 foo1Cache
或 foo12ache
的任何信息。它所知道的是,可以有任何类型为 string
的键保存类型为 CacheWithExpiry<CacheTypes, CacheNames>
的值。这就是为什么当您访问 cacheMap
的 属性 时,TypeScript 不会知道具体的属性。
如果你去掉类型,TypeScript 将知道属性及其类型:
export const cacheMap = {
foo1Cache: new CacheWithExpiry<string, 'foo_1'>(),
foo2Cache: new CacheWithExpiry<number, 'foo_2'>()
} as const
cacheMap.foo1Cache // foo1Cache: CacheWithExpiry<string, "foo_1">
cacheMap
的类型现在是:
const cacheMap: {
readonly foo1Cache: CacheWithExpiry<string, "foo_1">;
readonly foo2Cache: CacheWithExpiry<number, "foo_2">;
}
如果在创建 cacheMap
对象时还需要类型验证,则需要将对象字面量传递给泛型函数。
function createCacheMap<T extends CacheMap<CacheTypes, CacheNames>>(cacheMap: T): T {
return cacheMap
}
export const cacheMap = createCacheMap({
foo1Cache: new CacheWithExpiry<string, 'foo_1'>(),
foo2Cache: new CacheWithExpiry<number, 'foo_2'>(),
anything: "string" // Error: Type 'string' is not assignable to type 'CacheWithExpiry<CacheTypes, CacheNames>
})
cacheMap.foo1Cache // foo1Cache: CacheWithExpiry<string, "foo_1">
我正在尝试创建一个对象,其中每个 属性 都映射到一个 class 实例。 class 类型依赖于两个泛型。当我在我的对象中访问 属性 时,TypeScript 将 属性 的类型推断为用于定义对象的联合类型,而不是 属性 本身的类型。
如何让 TypeScript 正确推断 属性 的类型?
这里有一段代码可以帮助澄清问题:
export class CacheWithExpiry<T extends CacheTypes, V extends CacheNames> {
constructor() {
}
...
}
export type CacheNames =
'foo_1' |
'foo_2'
type CacheTypes = string | number
type CacheMap<T extends CacheTypes, V extends CacheNames> = { [key: string]: CacheWithExpiry<T, V> }
export const cacheMap: CacheMap<CacheTypes, CacheNames> = {
foo1Cache: new CacheWithExpiry<string, 'foo_1'>(), // Type is inferred as expected 'CacheWithExpiry<string, "foo_1">'
foo2Cache: new CacheWithExpiry<number, 'foo_2'>()
} as const
cacheMap.foo1Cache// Type is inferred as 'CacheWithExpiry<CacheTypes, CacheNames>' instead of 'CacheWithExpiry<string, "foo_1">'
编辑 1:我还需要维护 cacheMap
的类型安全,因此从 cacheMap
中完全删除类型是行不通的。示例:
export const cacheMap = {
foo1Cache: new CacheWithExpiry<string, 'foo_1'>(),
foo2Cache: new CacheWithExpiry<number, 'foo_2'>(),
foo3: 'I am not a cache class instance', // I still want this to throw an error
} as const
您已将类型 CacheMap<CacheTypes, CacheNames>
分配给变量 cacheMap
。此类型不包含有关键 foo1Cache
或 foo12ache
的任何信息。它所知道的是,可以有任何类型为 string
的键保存类型为 CacheWithExpiry<CacheTypes, CacheNames>
的值。这就是为什么当您访问 cacheMap
的 属性 时,TypeScript 不会知道具体的属性。
如果你去掉类型,TypeScript 将知道属性及其类型:
export const cacheMap = {
foo1Cache: new CacheWithExpiry<string, 'foo_1'>(),
foo2Cache: new CacheWithExpiry<number, 'foo_2'>()
} as const
cacheMap.foo1Cache // foo1Cache: CacheWithExpiry<string, "foo_1">
cacheMap
的类型现在是:
const cacheMap: {
readonly foo1Cache: CacheWithExpiry<string, "foo_1">;
readonly foo2Cache: CacheWithExpiry<number, "foo_2">;
}
如果在创建 cacheMap
对象时还需要类型验证,则需要将对象字面量传递给泛型函数。
function createCacheMap<T extends CacheMap<CacheTypes, CacheNames>>(cacheMap: T): T {
return cacheMap
}
export const cacheMap = createCacheMap({
foo1Cache: new CacheWithExpiry<string, 'foo_1'>(),
foo2Cache: new CacheWithExpiry<number, 'foo_2'>(),
anything: "string" // Error: Type 'string' is not assignable to type 'CacheWithExpiry<CacheTypes, CacheNames>
})
cacheMap.foo1Cache // foo1Cache: CacheWithExpiry<string, "foo_1">