ChatGPT解决这个技术问题 Extra ChatGPT

Typescript中对象的键和值的类型

我有两组字符串值,我想将它们作为常量对象从一组映射到另一组。我想从该映射中生成两种类型:一种用于键,一种用于值。

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?,但要么我的改编错误,要么答案一开始就不适合我的场景。


a
artem

编译器会将字符串文字类型扩展为 string,除非满足某些特定条件,如 github issuesPR 中所述,或者 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"

完美的。我扫描了几个提出这个问题的问题,但认为编译器不会运行该函数,所以我跳过了解决方案。掌心
D
Dharman

实际上,您应该将 KeyToVal 更改为以下声明:

const KeyToVal = {
    MyKey1: 'myValue1',
    MyKey2: 'myValue2',
} as const; // <----- add the <as const> here

然后创建键类型:

type Keys = keyof typeof KeyToVal;

现在您可以创建值的类型:

type ValuesTypes = typeof KeyToVal[Keys];

s
setdvd

您试图从对象(可以有任意数量的键/值)推断类型。您可以尝试先描述类型(或者更好的接口),然后像这样推断 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 的运行时访问权限。
N
Naeem Baghi

我知道它可能不相关,但对于我的用例,我遇到了这个问题,因为我想创建一个基于对象或数组的类型。所以我只是认为对于具有相同用例的人来说使用枚举可能很有用:您可以像这样简单地定义一个枚举:

enum Arrow {
  Up,
  Down,
  Left,
  Right
}

您可以阅读有关它们的更多信息 herehere

您现在可以将此枚举用作类型:

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} />

l
lee_mcmullen

不太一样,但是如果你有一个对象数组而不是单个对象,那么你可以通过执行以下操作提取已知属性的值来创建一个类型:

const keyToValArray = [
  { value: 'myValue1', label: 'myLabel1' },
  { value: 'myValue2', label: 'myLabel2' }
] as const;
type Keys = typeof keyToValArray[number]['value']; // 'myValue1' | 'myValue2'