首页 > 解决方案 > 为什么类型谓词的类型必须可以分配给它的参数类型?

问题描述

我有一个类型谓词:

// 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,而是我们为每种类型提供 1 个类型保护函数,即a -> Boolean每个a.

打字稿抱怨说:

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

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

标签: typescript

解决方案


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

如果值的类型和类型谓词中的类型之间没有关系,那么守卫将毫无意义。例如,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值永远不会是 a string,所以守卫是没有意义的:它的运行时检查是不必要的,应该总是 return 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,但反之则不然。


推荐阅读