TypeScript

type predicate

通常来讲,收缩数组元素为子类型,直接用 as 即可,但可以试试 ts 推荐的写法

  1. const fields = ['111', { value: '111', type: 'shit' }];
  2. const a = (fields.find(
  3. (i) => typeof i !== 'string' && !!i.type,
  4. ) as { value: string; type: string })?.value;

通过查看 find 类型,可以看到 find 函数也确实是可以通过传递泛型参数,收缩返回值类型的,但光传泛型参数,去除 as 会有类似的报错:
image.png
报错信息中,提到该函数签名不对,必须得是一个 type predicate。
关于 predicate 的定义,predicate 是一个入参为类型,返回值为 boolean 类型的纯函数,表面看是签名符合,但未在类型层面表达,isxxx 这个语义(isxxx 是一个收缩类型的语义,代表此时的类型是入参类型的子类型),查看 find 类型签名,也可看到:
image.png
type predicate 需要显式定义一个 value is S,且 S 与入参类型 T 存在子类型约束
所以可以实现如下的内容,代替 as:

  1. const a = fields.find(
  2. (i): i is { value: string; type: string } => typeof i !== 'string' && !!i.type,
  3. )?.value;

不过其实大差不差,只是可能看着正规了一些,毕竟 is 语法,并不与函数体内类型产生交互,也就是当前 ts 的上下文验证功能还不够:
image.png
照 ts 的发展趋势可能有所改变,也可能永不会改变。
所以,为了减少外部噪音,可以将所有的 predicate 函数,单独定义,使用时不再重新定义,而是直接调用 isXxx 函数。