我遇到了一个问题,试图让 typescript 为我识别 javascript 对象的键,同时强制每个键的值类型,因为我想创建对象键的类型,所以我不能只创建一个常规 type MyObject = { [key: string]: <insert type> }
.
想象一个物体 myobject
我在其中提取它的键,例如:
const myobject = {
foo: {},
bar: {}
};
type MyObjectKeys = keyof typeof myobject; // 'foo' | 'bar'
如何向键的值添加类型定义,同时仍然能够提取/继承键的定义?如果我做这样的事情,那么我将不再能够提取对象的确切键,而只能提取类型(字符串):
type MyObject = { [key: string]: { value: boolean }}
const myobject = {
foo: { value: true },
bar: { value: false }
};
type MyObjectKeys = keyof typeof myobject; // string
我想我可以通过创建一个辅助函数来实现这一点,例如:
function enforceObjectType<T extends MyObject>(o: T) {
return Object.freeze(o);
}
const myobject = enforceObjectType({
foo: {},
bar: {}
});
但是我更愿意为它定义一个明确的类型,而不必污染代码,只编写与类型相关的函数。有没有办法允许一组字符串作为一个类型的键而不重复?
这样做的目的是让 TypeScript 帮助指出正确的对象键,例如(实际用法有点复杂,所以我希望这能很好地描述它):
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
收尾:我想将一个对象定义为 const (实际上是
Object.freeze
)并且能够:string
而不是它们是什么 - 比如 '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.
根据上述,我不能执行以下操作,因为这会将已知键覆盖为任何字符串:
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
另一个例子:见this gist例如并将其复制到 typescript playground如果你想改变代码
最佳答案
希望这对你现在有帮助:
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
游乐场link .
关于具有定义值的 Typescript 动态对象键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61013605/