我正在尝试将对象转换为动态创建的类型。但是我在努力做到正确。
假设我有一个对象:
const constants = {
filter: 'flr',
color: 'col'
}
我将如何进行输入,这将允许以下操作:
type MetaData = {
flr: number
col: string
}
//js
const meta: MetaData = getMeta();
const filterValue: number = meta[constants.filter];
每当常量值之一更改时,我都希望类型也自动更新。
我尝试通过以下操作进行设置:
type MetaData = {
[constants.filter]: number
[k: constants.filter]: number
[k: any extends constants.filter]: number
}
但是似乎没有任何效果,而且我似乎无法为此找到合适的解决方案。有任何有关工作类型的提示吗?
答案 0 :(得分:2)
const constants = {
filter: 'flr',
color: 'col'
} as const; // very important
type Constants = typeof constants; // represents the type of the constants object
type ConstantsValues = Constants[keyof Constants] // defines values of constants object
type MetaData = {
[K in ConstantsValues]: any // map which has all keys as values of constants object
}
// using
const meta: MetaData = {
flr: 1,
col: 2
}
const filterValue: number = meta[constants.filter];
说明
最重要的是将constants
定义为const,这意味着我们说的是对象的这种结构是永久性的,并且推断出的类型应该精确地做到这一点。感谢const
,typeof constants
定义了对象拥有的确切键和值。
接下来的事情是Constants
和ConstantsValues
这两种类型,它们只是来自constants
对象的类型的简单定义。它们是出于可读性目的。
最后一个是MetaData
。我们将其定义为map,其中哪些键都是constants
对象的值。我将值设置为any
,因为您没有定义对此的需要。
constants
对象的任何更改都会影响更改Metadata
类型的每个实例的需要。
如果整个Metadata
对象应该具有一种类型的值(如示例中的number
所示),则可以通过以下方式实现:
type MetaData = {
[K in ConstantsValues]: number // here we have a number for all values
}
或更复杂的方式:
type MetaData<V> = {
[K in ConstantsValues]: V // here we have V for all values
}
type MetaDataStr = MetaData<string>
type MetaDataNum = MetaData<number>
评论中还要求其他需求。需要能够定义将用不同类型的值表示constants
对象的一部分的类型。这是实现该示例的示例:
// bigger object to have an example
const constants = {
filter: 'flr',
color: 'col',
rank: 'rnk',
size: 'sz'
} as const;
// the same two types as previous
type Constants = typeof constants;
type ConstantsValues = Constants[keyof Constants];
// create parts of values
type PartOfConstantsA = Extract<ConstantsValues, 'flr' | 'col'>
type PartOfConstantsB = Extract<ConstantsValues, 'rnk' | 'sz'>
// create more generic type in order to pass also keys by Keys generic
type MetaData<Keys extends PropertyKey, Values> = {
[K in Keys]: Values
}
// we combine both types by &
type FinalMetaData = MetaData<PartOfConstantsA, number> & MetaData<PartOfConstantsB, string>;
// using
const meta: FinalMetaData = {
flr: 1, // needs to be number
col: 2,// needs to be number
rnk: 'a', // needs to be string
sz: 'b' // needs to be number
}
const filterValue = meta[constants.filter];