【问题标题】:Why must a type predicate's type be assignable to its parameter's type?为什么类型谓词的类型必须可以分配给它的参数类型?
【发布时间】:2018-10-29 11:13:04
【问题描述】:

我有一个类型谓词:

// tslint:disable-next-line:no-any
const isString = (value: any): value is string {
  return typeof value === 'string'
}

这可行,但它要求我禁用我的 linter。我宁愿这样做:

const isString = <T>(value: T): value is string {
  return typeof value === 'string'
}

这样类型不是any,而是每个类型都有一个类型保护函数,即每个a一个函数a -&gt; Boolean

Typescript 抱怨说:

类型谓词的类型必须可分配给其参数的类型。 类型“字符串”不可分配给类型“T”。

这对我来说没有意义......为什么类型谓词的类型很重要?

【问题讨论】:

  • 您可以改用(value: {}): value is string =&gt; { ... }。至于错误,很奇怪;似乎倒退了。 T 需要分配给 string 对我来说更有意义。例如,TypeScript 应该知道 Date 永远不会分配给 string,所以这样的谓词没有意义。
  • 嗯...但是允许我们使用(value: any) =&gt; value is string 作为类型谓词更糟糕,对吧?如果我愿意,我可以给它一个Date
  • 有点不同。使用T 更像是编写一大堆函数。尝试编写一个用户定义的类型保护,如(value: Date): value is string =&gt; { ... },你就会明白我的意思了。
  • 好点,泛型的意思是“给我每个函数中的一个a -&gt; Boolean”,所以如果这些函数中的任何一个不存在,那么泛型就不存在。好的!你能写一个答案吗?

标签: typescript


【解决方案1】:

除了已接受的答案之外,如果您碰巧需要对 mixin 使用类型保护,您也会收到此错误,因为 is 运算符的行为不像 implements 那样。

interface Animal { ... }

interface Climber { ... }

interface Ape extends Animal, Climber { ... } 

const isClimberMixin = (animal: Animal): animal is Climber => ...

此类代码失败,因为 Climber 不能分配给 Animal,因为它没有从它扩展。

如果无法避免 mixin 模式,解决方案是使用联合类型:

const isClimberMixin = (animal: Animal): animal is Animal & Climber => ...

【讨论】:

    【解决方案2】:

    用户定义的类型保护执行运行时检查以确定特定类型的值是否满足类型谓词。

    如果值的类型和类型谓词中的类型之间没有关系,那么守卫就没有意义了。例如,TypeScript 不允许这样的用户定义保护:

    function isString(value: Date): value is string {
        return typeof value === "string";
    }
    

    并且会产生这个错误:

    [ts] A type predicate's type must be assignable to its parameter's type.
    Type 'string' is not assignable to type 'Date'.
    

    Date 值永远不会是string,因此守卫毫无意义:它的运行时检查是不必要的,应该始终返回false

    当您指定一个通用的、用户定义的类型保护时,T 可以是任何东西,所以 - 与 Date 一样 - 对于某些类型,类型保护没有意义。

    如果你真的不想使用any,你可以使用一个空的接口——{}——来代替:

    function isString(value: {}): value is string {
        return typeof value === "string";
    }
    

    如果您还想允许将 nullundefined 值传递给守卫,您可以使用:

    function isString(value: {} | null | undefined): value is string {
        return typeof value === "string";
    }
    

    关于错误消息,谓词类型必须可分配给值类型,因为类型保护用于检查具有较少特定类型的值是否实际上是具有更特定类型的值。例如,考虑这个守卫:

    function isApe(value: Animal): value is Ape {
        return /* ... */
    }
    

    Ape 可以分配给Animal,但反之则不行。

    【讨论】:

      猜你喜欢
      • 2023-02-16
      • 1970-01-01
      • 2019-06-24
      • 2021-06-14
      • 1970-01-01
      • 2021-02-03
      • 1970-01-01
      • 2018-08-10
      相关资源
      最近更新 更多