typescript映射的元组查找类型



既然typescript 3.1引入了映射元组类型,我希望这个代码示例能起作用:

export interface SettingKey {
General_Language: 'en' | 'sl';
Map_InitialLongitude: number;
Map_InitialLatitude: number;
}
export function fetchSetting<K extends (keyof SettingKey)[]>
(...keys: K): Promise<SettingKey[K]> {
return null as any;
}
fetchSetting('General_Language', 'Map_InitialLongitude').then(x => {
return x['General_Language'] === 'de' // would want compilation error 'de' not in 'en' | 'sl'
})

但事实并非如此。错误为:

ttt.ts:7:83 - error TS2536: Type 'K' cannot be used to index type 'SettingKey'.
7 export function fetchSetting<K extends (keyof SettingKey)[]>(...keys: K): Promise<SettingKey[K]> {
              ~~~~~~~~~~~~~
ttt.ts:11:12 - error TS2571: Object is of type 'unknown'.
11     return x['General_Language'] === 'de'
~

显然,第二个错误是第一个错误的结果,所以这并不是一个真正的问题。第一个是有问题的。

keys是keyof SettingKey的数组,所以我希望SettingKey[K]是列出属性的类型的数组(所以,具体地说,在我放的代码示例中,它将是['en' | 'sl', number]

如果T是数组类型S[],我们映射到数组类型R[],其中R是X的实例化,其中S取代了T[p]。

但我想这只适用于映射类型,这里我有一个查找类型,这就是为什么它不起作用的原因吧?

我想我想表达的是清楚的;这可以在typescript中实现类型安全吗?

要有一个映射的元组,您需要一个映射类型,它将把原始元组(在类型参数K中(映射到新的元组类型

export interface SettingKey {
General_Language: 'en' | 'sl';
Map_InitialLongitude: number;
Map_InitialLatitude: number;
}
type SettingKeyProp<P extends keyof SettingKey> = SettingKey[P]
type SettingKeyArray<K extends { [n: number]: keyof SettingKey }> = {
[P in keyof K]: K[P] extends keyof SettingKey ? SettingKey[K[P]]: never 
} 
export function fetchSetting<K extends (keyof SettingKey)[]>
(...keys: K): Promise<SettingKeyArray<K>> {
return null as any;
}
fetchSetting('General_Language', 'Map_InitialLongitude').then(x => {
// x[0] is 'en' | 'sl'
return x[0] === 'de' /// since you want a tuple, you should index by number not name
})

如果你想按名称进行索引,这也是可能的,但映射的类型应该映射到数组中的值,而不是数组中的键:

type SettingKeyArray<K extends { [n: number]: keyof SettingKey }> = {
[P in K[number]]: SettingKey[P] 
} 
export function fetchSetting<K extends (keyof SettingKey)[]>
(...keys: K): Promise<SettingKeyArray<K>> {
return null as any;
}
fetchSetting('General_Language', 'Map_InitialLongitude').then(x => {
// you can access by name
return x.General_Language === 'de' 
}) 

最新更新