How to make “handler” lookup for “dispatcher” style function be typed correctly

后端 未结 1 1801
一生所求
一生所求 2021-01-21 06:39

Supposed I have a type like this:

type TInfoGeneric = {
  valueType: TType,
  value: T         


        
1条回答
  •  -上瘾入骨i
    2021-01-21 07:38

    Yeah, there's no convenient and type-safe solution for you here. I've opened an issue about this but I fully expect the answer will be "it's too much work for not enough benefit to address this".

    I see two main ways forward. One is to just use a type assertion, since you legitimately know more than the compiler does here. It could be like this:

    function handleInfo(info: TInfo) {
        // assert your way out.  Not type safe but convenient!
        (handlers[info.valueType] as (x: number | string)=>any)(info.value); 
    }
    

    Now there's no error. It's not type safe. But it's convenient and doesn't change the emitted JavaScript.


    Or you could try to walk the compiler through the cases and prove to it that all is fine. This is complex, brittle, and has runtime effects:

    const typeGuards: {
      [P in keyof TInfoTypeMap]: (x: TInfoTypeMap[keyof TInfoTypeMap])=>x is TInfoTypeMap[P];
    } = {
        num: (x:any): x is number => typeof x === "number",
        str: (x:any): x is string => typeof x === "string"
    }
    
    function narrowTInfo(
      x: TInfo, v: K): x is TAllPossibleTInfoMap[K] {
        return typeGuards[v](x.value);
    } 
    
    function handleInfo(info: TInfo) {
        if (narrowTInfo(info, "num")) {
            handlers[info.valueType](info.value); // okay
        } else {
            handlers[info.valueType](info.value); // okay
        }
    }
    

    That works but is obnoxious. So I'd recommend an assertion.

    Hope that helps; good luck!

    0 讨论(0)
提交回复
热议问题