【问题标题】:TypeScript: Type inference + Generic Type + "prop" in condition throws an errorTypeScript:类型推断+通用类型+条件中的“prop”会引发错误
【发布时间】:2020-12-19 13:48:17
【问题描述】:

我在一个项目中遇到了以下问题(抽象),如果我做错了什么,我真的很困惑:

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 会引发错误。这是为什么呢?

感谢所有答案。

【问题讨论】:

    标签: typescript type-inference typescript-generics


    【解决方案1】:

    似乎 typescript 需要为您的案例提供明确的类型保护。定义简单的单级类型保护函数的动态方法是

    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])
        })
    }
    

    在顶级类型保护中,我省略了 value typeof 匹配检查,因为您的隐式类型保护条件似乎并不关心 prop 的值。

    Playground Link

    【讨论】:

      猜你喜欢
      • 2018-10-20
      • 1970-01-01
      • 2018-10-13
      • 1970-01-01
      • 2012-11-26
      • 2021-06-12
      • 1970-01-01
      • 2020-09-22
      • 2019-09-17
      相关资源
      最近更新 更多