我有两组字符串值,我想将它们作为常量对象从一组映射到另一组。我想从该映射中生成两种类型:一种用于键,一种用于值。
const KeyToVal = {
MyKey1: 'myValue1',
MyKey2: 'myValue2',
};
关键很简单:
type Keys = keyof typeof KeyToVal;
我无法获得值的编译时类型。我想也许其中一个会起作用:
type Values = typeof KeyToVal[Keys];
type Values<K> = K extends Keys ? (typeof KeyToVal)[K] : never;
type Prefix<
K extends Keys = Keys,
U extends { [name: string]: K } = { [name: string]: K }
> = {[V in keyof U]: V}[K];
所有这些都使 Values
成为 string
。我还尝试将这两个答案改编为 How to infer typed mapValues using lookups in typescript?,但要么我的改编错误,要么答案一开始就不适合我的场景。
编译器会将字符串文字类型扩展为 string
,除非满足某些特定条件,如 github issues 和 PR 中所述,或者 const assertion 用于文字值。 const 断言出现在 TypeScript 3.4 中:
const KeyToVal = {
MyKey1: 'myValue1',
MyKey2: 'myValue2',
} as const;
type Keys = keyof typeof KeyToVal;
type Values = typeof KeyToVal[Keys]; // "myValue1" | "myValue2"
在 3.4 之前,有一种变通方法可以获得相同的效果。为了使编译器推断文字类型,您必须通过具有适当制作的泛型类型参数的函数传递对象,这似乎可以解决这种情况:
function t<V extends string, T extends {[key in string]: V}>(o: T): T {return o}
这个函数的全部目的是捕获和保存类型以启用类型推断,否则它完全没用,但有了它你可以拥有
const KeyToVal = t({
MyKey1: 'myValue1',
MyKey2: 'myValue2',
});
type Keys = keyof typeof KeyToVal;
type Values = typeof KeyToVal[Keys]; // "myValue1" | "myValue2"
实际上,您应该将 KeyToVal
更改为以下声明:
const KeyToVal = {
MyKey1: 'myValue1',
MyKey2: 'myValue2',
} as const; // <----- add the <as const> here
然后创建键类型:
type Keys = keyof typeof KeyToVal;
现在您可以创建值的类型:
type ValuesTypes = typeof KeyToVal[Keys];
您试图从对象(可以有任意数量的键/值)推断类型。您可以尝试先描述类型(或者更好的接口),然后像这样推断 Kyes 和 Values:
type KeyToObjMap = {
some: "other",
more: "somemore",
};
type Keys = keyof KeyToObjMap;
type Values = KeyToObjMap[Keys];
let one: Values = "some";
let two: Values = "other";
let three: Keys = "some";
let four: Values = "somemore";
let five: Keys = "fun";
您将在 IDE 中获得正确的高亮显示。
https://i.stack.imgur.com/fDwpG.png
KeyToObjMap
的运行时访问权限。
我知道它可能不相关,但对于我的用例,我遇到了这个问题,因为我想创建一个基于对象或数组的类型。所以我只是认为对于具有相同用例的人来说使用枚举可能很有用:您可以像这样简单地定义一个枚举:
enum Arrow {
Up,
Down,
Left,
Right
}
您现在可以将此枚举用作类型:
type Props = {
arrow: Arrow
}
const Component = (props: Props) => {
switch(props.arrow) {
case Arrow.Up:
// go-up
case Arrow.Down:
// go-down
...
}
}
你可以在你的组件中使用它:
<Component arrow={Arrow.top} />
不太一样,但是如果你有一个对象数组而不是单个对象,那么你可以通过执行以下操作提取已知属性的值来创建一个类型:
const keyToValArray = [
{ value: 'myValue1', label: 'myLabel1' },
{ value: 'myValue2', label: 'myLabel2' }
] as const;
type Keys = typeof keyToValArray[number]['value']; // 'myValue1' | 'myValue2'