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

使用“推断”关键字创建反向类型查找?

  •  1
  • dwjohnston  · 技术社区  · 5 年前

    以下是我所拥有的,我有各种类型,我有一个用于该类型的字符串表示:

    type PossibleValueTypes = Color | number | Position;
    type PossibleValueTypesAsString = "color" | "number" | "position";
    
    type ValueTypeMap = {
      "color" : Color; 
      "number" : number; 
      "position" : Position; 
    }; 
    
    

    现在,给出一个给定的字符串表示,例如,返回值类型非常简单;

    
    function generateRandomValueOfType<T extends PossibleValueTypesAsString>(type: T) : ValueTypeMap[T] {
        if (type === 'color') {
            return {
                r: 1, 
                g: 1, 
                b: 1, 
                a: 1, 
            } as ValueTypeMap[T]
        }
        if (type === "position") {
            return {
                x:1, 
                y: 1
            } as ValueTypeMap[T]
        }
    
        if (type === "number") {
            return 1 as ValueTypeMap[T]; 
        }
    
        throw new Error ("We shouldn't have got here"); 
    }; 
    
    
    const a: Position = generateRandomValueOfType("position"); 
    const b: number = generateRandomValueOfType("position"); // Expected error!
    
    

    现在的问题是——如果我想做相反的事情,也就是说——给定一个值类型,确定字符串表示形式。

    我能做的最好的事情就是做一个链式条件句,比如:

    type ReverseValueTypeLookup<T extends PossibleValueTypes>  = T extends Color ? "color" : T extends number ? "number" : T extends Position ? "position": never; 
    
    function hasAValueAcceptingCallback<T extends PossibleValueTypes> (callback: (value: T) => void, valueTypeAsString: ReverseValueTypeLookup<T>)  {
        const value = generateRandomValueOfType(valueTypeAsString); 
    
      //Argument of type 'ValueTypeMap[ReverseValueTypeLookup<T>]' is not assignable to parameter of type 'T'.
      //'ValueTypeMap[ReverseValueTypeLookup<T>]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'PossibleValueTypes'.
        callback(value);
    }
    
    
    
    
    
    
    

    但在我给出的例子中,这实际上不起作用。

    有没有更整洁的方法来实现我在这里尝试做的这两件事?

    TS Playground

    1 回复  |  直到 5 年前
        1
  •  2
  •   T.D. Stoneheart    5 年前

    一个非常详细但有效的解决方案是。。。

    type ReverseValueTypeLookup<T extends ValueTypeMap[keyof ValueTypeMap]> = {
      [x in keyof ValueTypeMap]: ValueTypeMap[x] extends T ? x : never;
    }[keyof ValueTypeMap];
    // exclude key x when ValueTypeMap[x] is not assignable to T, and then get the types of values
    
    type C = ReverseValueTypeLookup<Color>; // type 'color'
    type N = ReverseValueTypeLookup<number>; // type 'number'
    

    如果你仍然不能区分不同的类型 Color | number | Position ,使用类型缩小,如。。。

    var data: Color | number | Position;
    if (typeof data === 'number') {
      // data is number
    } else if ('r' in data) {
      // data is Color
    } else if ('x' in data) {
      // data is Position
    }
    
    推荐文章