代码之家  ›  专栏  ›  技术社区  ›  Ooker

如何自动键入预定义对象的键和值?

  •  -1
  • Ooker  · 技术社区  · 2 年前

    我有一个映射对象和一个助手函数来从值中获取键,如下所示:

    const map = {
        0: 'a',
        1: 'b',
        2: 'c',
        3: 'd',
    }
    
    function getKey(value: Value): Key {
        return Object.keys(map).find(key => map[key] === value);
    }
    

    通常我必须打字 Key Value 手动方式如下:

    type Key = 0 | 1 | 2 | 3 | '0' | '1' | '2' | '3'
    type Value = 'a' | 'b' | 'c' | 'd'
    

    有办法避免那样做吗?其思想是对象可以更改,甚至可以是函数的结果。唯一可以确定的是键是数字,值是字符串,但我不想键入它太通用。我理解泛型的概念,但我不知道如何实现它。

    1 回复  |  直到 2 年前
        1
  •  1
  •   Ooker    2 年前

    你需要使用 as const 子句并反转对象,如下所示:
    https://tsplay.dev/mbaX2N
    非PropertyKey(string|number)值是否需要大小写?

    const map = {
      0: 'a',
      1: 'b',
      2: 'c',
      3: 'd',
    } as const
    // ^^^^^^^
    // const map: {
    //     readonly 0: "a";
    //     readonly 1: "b";
    //     readonly 2: "c";
    //     readonly 3: "d";
    // }
    
    type ValueOf<T> = T[keyof T]
    type MapKey = keyof typeof map;
    //   ^?
    // type MapKey = 0 | 1 | 2 | 3
    type MapValue = ValueOf<typeof map>
    //   ^?
    // type MapValue = "a" | "b" | "c" | "d"
    
    
    type Reverse<T extends Record<PropertyKey, PropertyKey>> = {
      [K in keyof T as T[K]]: K
    }
    type ReversedMap = Reverse<typeof map>
    // type ReversedMap = {
    //     readonly a: 0;
    //     readonly b: 1;
    //     readonly c: 2;
    //     readonly d: 3;
    // }
    
    function getKey<V extends ValueOf<typeof map>>(value: V): ReversedMap[V] {
      return Object.entries(map).find(([k, v]) => v === value)![0] as any
    }
    
    let a = getKey('a')
    //  ^?
    // let a: 0