【问题标题】:How can I write a user-defined type guard for a type discriminator?如何为类型鉴别器编写用户定义的类型保护?
【发布时间】:2021-06-19 01:30:07
【问题描述】:

假设我有对象使用_type_ 属性来编码运行时类型信息。

interface Foo {
  _type_: '<foo>';
  thing1: string;
}

interface Bar {
  _type_: '<bar>'
  thing2: number;
}

function helpme(input: Foo|Bar): string | number {
  if (input._type_ === '<foo>') {
    return input.thing1;
  }
  if (input._type_ === '<bar>') {
    return input.thing2;
  }
  return 'N/A';
}

这一切都很好,而且效果很好。但是,我想将_type_ 签入抽象为一个函数,这样我的调用站点就不必都知道这个属性,他们可以直接调用该函数。

interface Foo {
  _type_: '<foo>';
  thing1: string;
}

interface Bar {
  _type_: '<bar>'
  thing2: number;
}

function typeIs(o: any, t: '<foo>' | '<bar>'): o is {_type_: t} {
  return o && typeof(o) === 'object' && o._type_ === t;
}

function helpme(input: Foo|Bar): string | number {
  if (typeIs(input, '<foo>')) {
    return input.thing1;
  }
  if (typeIs(input, '<bar>')) {
    return input.thing2;
  }
  return 'N/A';
}

问题是,这实际上不起作用;我收到一个错误:

't' refers to a value, but is being used as a type here. Did you mean 'typeof t'?

...这是有道理的。我要写的语法怎么写?

https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgGIHt3IN4ChnID6YAngA4SEBcyA5ADwyYB8tA3PsmABagDmARhoBnMFH4cAvrlyhIsRCgBCcKDk7FylGgwBGq1px78ATDRABXALa7oUmTAsgEYYOhBctASWEAKdDRwICQANFw6jCy0yAA+dPT6UKwAlDRYwMI4mhTUXJLqBFAQYBZQHlgAZBWeFOgw-snIALwtdOi6AFYQLtFVyOgAdNmUza1g9riOzq7uyNwQADZkVhC+oGQWYDQY6DEqUKnIouIgfLHIljbQBcjAMMi+pBQ+ayAbYGEMTOgpjXgEhWKpQ8602A2MpwEHAI0gIdweTwgL1BH3iiV+N0BJTKtzeYIhfBM0OQsOQRWxHloADkAPQAQXYuGkQA

【问题讨论】:

    标签: typescript


    【解决方案1】:

    您正在尝试编写一个检查动态类型的类型保护。像这样的东西可以代替吗?

    interface Foo {
      _type_: '<foo>';
      thing1: string;
    }
    
    interface Bar {
      _type_: '<bar>'
      thing2: number;
    }
    
    function isFoo(o: any, typeEncoding: string = '<foo>'): o is Foo {
      return o && typeof(o) === 'object' && o._type_ === typeEncoding;
    }
    
    function isBar(o: any, typeEncoding: string = '<bar>'): o is Bar {
      return o && typeof(o) === 'object' && o._type_ === typeEncoding;
    }
    
    function helpme(input: Foo|Bar): string | number {
      if (isFoo(input)) {
        return input.thing1;
      }
      if (isBar(input)) {
        return input.thing2;
      }
      return 'N/A';
    }
    

    如果您打算保持一切动态,您可以尝试这样的解决方案, Dynamic type guard functions

    【讨论】:

    • 感谢您的回复。您的回复给了我一个想法,我将为此创建一个单独的答案。
    【解决方案2】:

    感谢 DKidwell 的回复,我有了使用重载来解决问题的想法(我可以通过代码生成来创建):

    function typeIs(o: any, t: '<foo>'): o is Foo;
    function typeIs(o: any, t: '<bar>'): o is Bar;
    function typeIs(o: any, t: string): boolean {
      return o && typeof(o) === 'object' && o._type_ === t;
    }
    
    function helpme(input: Foo|Bar): string | number {
      if (typeIs(input, '<foo>')) {
        return input.thing1;
      }
      if (typeIs(input, '<bar>')) {
        return input.thing2;
      }
      return 'N/A';
    }
    

    不过,我不确定这是否是最有效的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-03
      • 2015-12-19
      • 1970-01-01
      • 2016-09-06
      • 2021-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多