【问题标题】:Types from both keys and values of object in TypescriptTypescript中对象的键和值的类型
【发布时间】:2019-05-08 18:54:29
【问题描述】:

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

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

【问题讨论】:

    标签: typescript typescript-typings


    【解决方案1】:

    编译器会将字符串文字类型扩展为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"
    

    【讨论】:

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

    您试图从对象(可以有任意数量的键/值)推断类型。您可以尝试先描述类型(或者更好的接口),然后像这样推断 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 中获得正确的高亮显示。

    【讨论】:

    • 几乎有效。现在我需要运行时访问KeyToObjMap
    【解决方案3】:

    其实你应该把KeyToVal改成下面的声明:

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

    然后创建键类型:

    type Keys = keyof typeof KeyToVal;
    

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

    type ValuesTypes = typeof KeyToVal[Keys];
    

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 2019-04-05
        • 1970-01-01
        • 2017-06-11
        • 2020-10-12
        • 2019-10-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多