[英]Typescript dynamic object keys with defined values
I am encountering an issue trying to make typescript recognise the keys of a javascript object for me, while enforcing each key's value type because I want to create a typeof the keys of the object, so I can't just create a regular type MyObject = { [key: string]: <insert type> }
. I am encountering an issue trying to make typescript recognise the keys of a javascript object for me, while enforcing each key's value type because I want to create a typeof the keys of the object, so I can't just create a regular
type MyObject = { [key: string]: <insert type> }
。
Imagine an object myobject
where I extract the keys of it like:想象一个 object
myobject
我提取它的键,如:
const myobject = {
foo: {},
bar: {}
};
type MyObjectKeys = keyof typeof myobject; // 'foo' | 'bar'
How can I add type definitions to the values of the keys, while still being able to extract/inherit the definitions of the keys?如何将类型定义添加到键的值中,同时仍然能够提取/继承键的定义? If I do something like this, then I will no longer be able to extract the exact keys of the object, but only the type (string):
如果我这样做,那么我将不再能够提取 object 的确切键,而只能提取类型(字符串):
type MyObject = { [key: string]: { value: boolean }}
const myobject = {
foo: { value: true },
bar: { value: false }
};
type MyObjectKeys = keyof typeof myobject; // string
I figured that I could achieve this by creating a helper function like:我想我可以通过创建一个助手 function 来实现这一点,例如:
function enforceObjectType<T extends MyObject>(o: T) {
return Object.freeze(o);
}
const myobject = enforceObjectType({
foo: {},
bar: {}
});
But I'd prefer to define a clear type for it, without having to pollute the code, writing functions only related to types.但是我更愿意给它定义一个明确的类型,不用污染代码,只写与类型相关的函数。 Is there a way to allow a set of strings as keys of a type without repetition?
有没有办法允许一组字符串作为一种类型的键而不重复?
The purpose of this is to get TypeScript to help pointing out the right object keys like (the real usage is a bit more complex, so I hope this describes it well enough):这样做的目的是让 TypeScript 帮助指出正确的 object 键(实际用法有点复杂,所以我希望这描述得足够好):
type MyObjectKeys = keyof typeof myobject; // string
function getMyObjectValue(key: MyObjectKeys) {
const objectValue = myobject[key];
}
// suggest all available keys, while showing an error for unknown keys
getMyObjectValue('foo'); // success
getMyObjectValue('bar'); // success
getMyObjectValue('unknown'); // failure
Wrap up: I want to define an object as const (in fact with Object.freeze
) and be able to:总结:我想将 object 定义为 const (实际上是
Object.freeze
)并能够:
string
instead of what they are - like 'foo' | 'bar'
string
而不是它们的本质——比如'foo' | 'bar'
'foo' | 'bar'
. 'foo' | 'bar'
。type GameObj = { skillLevel: EnumOfSkillLevels }; // ADD to each key.
const GAMES_OBJECT = Object.freeze({
wow: { skillLevel: 'average' },
csgo: { skillLevel 'good' }
)};
type GamesObjectKeys = keyof typeof GAMES_OBJECT;
function getSkillLevel(key: GamesObjectKeys) {
return GAMES_OBJECT[key]
}
getSkillLevel('wow') // Get the actual wow object
getSkillLevel('unknown') // Get an error because the object does not contain this.
In accordance to above, I can't do the following because that will overwrite the known keys to just any string:根据上述,我不能执行以下操作,因为这会将已知键覆盖为任何字符串:
type GameObj = { [key: string]: skillLevel: EnumOfSkillLevels };
const GAMES_OBJECT: GameObj = Object.freeze({
wow: { skillLevel: 'average' },
csgo: { skillLevel 'good' }
)};
type GamesObjectKeys = keyof typeof GAMES_OBJECT;
function getSkillLevel(key: GamesObjectKeys) {
return GAMES_OBJECT[key]
}
getSkillLevel('wow') // Does return wow object, but gives me no real-time TS help
getSkillLevel('unknown') // Does not give me a TS error
Another example: See this gist for example and copy it to typescript playground if you want to change the code另一个例子:如果你想更改代码,请参阅此要点并将其复制到typescript 操场上
Hope this help you now:希望现在对您有所帮助:
enum EnumOfSkillLevels {
Average = 'average',
Good = 'good'
}
type GameObject<T extends { [key: string]: {skillLevel: EnumOfSkillLevels} }> = {
[key in keyof T ]: {skillLevel: EnumOfSkillLevels}
}
const GAMES_OBJECT = {
wow: { skillLevel: EnumOfSkillLevels.Average },
csgo: { skillLevel: EnumOfSkillLevels.Good },
lol: { skillLevel: EnumOfSkillLevels.Good }
} as const;
function getSkillLevel(key: keyof GameObject<typeof GAMES_OBJECT>) {
return GAMES_OBJECT[key]
}
getSkillLevel('wow') // Does return wow object, but gives me no real-time TS help
getSkillLevel('lol') // Does return wow object, but gives me no real-time TS help
getSkillLevel('unknown') // Does give me a TS error
While I have not found a way to completely avoid creating a javascript function to solve this (also told that might not be possible at all, at this moment), I have found what I believe is an acceptable solution:虽然我还没有找到一种方法来完全避免创建 javascript function 来解决这个问题(也告诉这可能根本不可能,此时此刻),我找到了我认为是可接受的解决方案:
type GameInfo = { [key: string]: { skillLevel: 'good' | 'average' | 'bad' }}
type EnforceObjectType<T> = <V extends T>(v: V) => V;
const enforceObjectType: EnforceObjectType<GameInfo> = v => v;
const GAMES2 = enforceObjectType({
CSGO: {
skillLevel: 'good',
},
WOW: {
skillLevel: 'average'
},
DOTA: {
// Compile error - missing property skillLevel
}
});
type GameKey2 = keyof typeof GAMES2;
function getGameInfo2(key: GameKey2) {
return GAMES2[key];
}
getGameInfo2('WOW');
getGameInfo2('CSGO');
getGameInfo2('unknown') // COMPILE ERROR HERE
This way we get:这样我们得到:
I have updated my Gist to include this example and you might be able to see it in practice on typescript playground .我已经更新了我的 Gist以包含这个示例,您也许可以在typescript 操场上实际看到它。
I write my codes in this way:我以这种方式编写代码:
function define<T>(o:T){
return o;
}
type Node = {
value: number,
key: string
}
const NODE_DIC = {
LEFT: define<Node>({
value: 1,
key: '1'
}),
RIGHT: define<Node>({
value: 2,
// compile error for missing `key`
})
}
Here is the type of the object:这是 object 的类型:
{
LEFT: Node;
RIGHT: Node;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.