代码之家  ›  专栏  ›  技术社区  ›  millimoose Tomasz Nurkiewicz

如何在未启用任何不安全的情况下写入类型保护?

  •  0
  • millimoose Tomasz Nurkiewicz  · 技术社区  · 7 年前

    我正试图通过使用更严格的lint规则集来加强我的TS代码,但是我正在努力实现动态性的合理使用。

    我正在做一个类型保护来检测某个东西是否是不可更改的(如果不是,则将其包装在一个数组中),除了抑制lint规则来告诉这是kosher之外,我不知道该告诉ts什么:

    function isIterable(obj: any): obj is Iterable<unknown> {
        return obj && typeof obj[Symbol.iterator] === 'function';
    }
    

    我尝试将此更改为:

    function isIterable(obj: undefined | {[Symbol.iterator]?: unknown}): obj is Iterable<unknown> {
        return !!obj && typeof obj[Symbol.iterator] === 'function';
    }
    

    编译时不使用 any ,但它并不有用,因为我想将未知类型的值传递给它。

    有没有一种“干净”的说法“是的,我实际上想依靠JS返回” undefined 是否访问对象上不存在的属性?尤其是,因为这是一种写作风格的守卫。

    2 回复  |  直到 7 年前
        1
  •  1
  •   jcalz    7 年前

    我不知道像“没有不安全的东西”这样的东西是否会让你在 实施 A的 user-defined type guard ,因为通常这种类型保护的要点是允许编译器缩小其通常无法通过内置控制流缩小的值。我当然理解在这种实现中挂起一个linter规则。

    但我认为你几乎可以得到你想要的行为:

    function isIterable(obj: unknown): obj is Iterable<unknown> {
      if ((typeof obj !== 'object') || (obj === null)) return false; 
      // obj is now type object
      const wObj: { [Symbol.iterator]?: unknown } = obj; // safely widen to wObj
      return typeof wObj[Symbol.iterator] === 'function'; 
    }
    

    这是几个环跳,但想法是使用控制流缩小到狭窄 unknown object 然后加宽 对象 特别是对于具有您试图检查的可选属性的类型(这是通过引入一个新变量来实现的)。最后,检查加宽类型上该属性的类型。由于要检查的属性键是符号类型,因此需要在加宽类型中提到特定的属性名称。如果属性键是字符串,则可以使用 string index signature :

    function isPromise(obj: unknown): obj is Promise<unknown> {
      if ((typeof obj !== 'object') || (obj === null)) return false;
      // obj is now type object
      const wObj: {[k: string]: unknown} = obj; // safely widen to wObj
      return typeof wObj.then === 'function';
    }
    

    不管怎样,我希望这能让你更接近你的目标。祝你好运!

        2
  •  1
  •   Josh    7 年前

    另一个好策略是使用 Partial 用一个 as 铸造。

    interface RegularForm {
        regular: number;
    }
    
    interface FancyForm extends RegularForm {
        fancy: string;
    }
    
    const isFancyForm = (instance: RegularForm): instance is FancyForm =>
        (instance as Partial<FancyForm>).fancy !== undefined;
    
    推荐文章