TypeScript:类型推断+通用类型+条件中的“ prop”引发错误

时间:2020-08-31 12:28:28

标签: typescript type-inference typescript-generics

我在项目中遇到了以下问题(摘要),如果做错了事,我真的很困惑:

const fooState = {
  normal: {
    normalProp: "string",
  },
  normal2: {
    normalProp: 0,
  },
  weird: {
    weirdProp: "anything",
  },
};

type fooKeys = keyof typeof fooState;

export const getFooState = <T1 extends fooKeys>(arg: T1) => {
  const foundState = fooState[arg];
  if ("weirdProp" in foundState) {
    console.log(foundState.weirdProp); // This line throws an error, even though it is a practical possibility.
  }

  return foundState;
};

代码足以说明我的问题。我的目标是在foundState对象具有特定属性时以不同方式处理特定情况。

在我的示例中,如果参数arg作为"weird"传递,则控制台日志将/应该触发,但TS引发错误。为什么呢?

我很感谢所有答案。

1 个答案:

答案 0 :(得分:0)

好像打字稿需要为您的案例提供显式的类型保护。定义简单的单级类型保护功能的动态方法是

function dynamicCheckTopLevel<V>(a:any,b:V): a is V {
    let keys = Object.keys(b)
    return keys.every(k => k in a)
}

您还可以使用专门用于该道具的类型保护,这样您就可以显式地知道该类型,而不是派生自具有键值样本值的传入对象

function weirdCheck(x:any): x is {weirdProp:any}{
  return x.weirdProp;
}

然后错误消失

export const getFooState = <T1 extends fooKeys>(arg: T1) => {
  const foundState = fooState[arg];
  if (dynamicCheckTopLevel(foundState, {weirdProp:5})) { //had to give weirdProp a value, for your purpose it can be anything
    console.log(foundState.weirdProp); 
  }

  return foundState;
};

如果您想使用更深层次的动态类型防护,可以使用

function dynamicDeepCheck<V>(a:any,b:V): a is V {
    let keys = Object.keys(b) as Array<keyof V>
    return keys.every(key => {
      if(typeof b[key] === "object"){ 
        return dynamicDeepCheck(a[key], b[key])
      }
      return (a[key] && typeof a[key] === typeof b[key])
    })
}

在顶级类型防护中,由于您的隐式类型防护条件似乎并不在乎prop的值,因此我省略了值类型匹配检查。

Playground Link