You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript ts18047错误:filter函数中s可能为null的问题排查

Stream的filter函数TypeScript类型收窄异常

近期启用旧代码并添加TypeScript类型定义时,遇到了一个类型检查问题:在filter函数的闭包() => filter(s.next(), fn)处,TypeScript提示s可能为null,但此时代码处于while(s)分支内,s理应已被收窄为非null类型。类似逻辑的toArray函数能正常完成类型收窄,而通过const临时绑定s即可解决该错误。

Memo定义

type Memo<T> = () => T

function memo<T>(fn: () => T): Memo<T> {
  let value: undefined | T = undefined
  return () => {
    if (value === undefined) value = fn()
    return value
  }
}

Stream定义

type Stream<T> = null | {
  value: T
  next: () => Stream<T>
}

function stream<T>(value: T, next: () => Stream<T>): Stream<T> {
  return {
    value,
    next: memo(next),
  }
}

报错的map和filter函数

function map<T, U>(s: Stream<T>, fn: (t: T) => U): Stream<U> {
  if (s) {
    return stream(
      fn(s.value),
      () => map(s.next(), fn), // ✅ s类型已收窄为非null,无报错
    ) 
  }
  return null
}

function filter<T>(s: Stream<T>, fn: (t: T) => boolean): Stream<T> {
  while (s) {
    if (fn(s.value)) {
      return stream(
        s.value,
        () => filter(s.next(), fn), // ❌ TypeScript提示:s可能为null
      )
    }
    s = s.next()
  }
  return null
}

类型收窄正常的toArray函数

function toArray<T>(s: Stream<T>): Array<T> {
  const r: Array<T> = []
  while (s) {
    r.push(s.value) // ✅ s类型已收窄为非null,无报错
    s = s.next()
  }
  return r
}

解决方法

将当前非null的s绑定到一个const变量上,固定其类型,避免闭包引用时受后续重赋值的影响:

function filter<T>(s: Stream<T>, fn: (t: T) => boolean): Stream<T> {
  while (s) {
    if (fn(s.value)) {
      const m = s                   // ✅ 用常量保存当前非null的s
      return stream(
        m.value,
        () => filter(m.next(), fn), // ✅ m类型固定为非null,无报错
      )
    }
    s = s.next()
  }
  return null
}

内容的提问来源于stack exchange,提问作者Mulan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 22:41:22