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

TypeScript实现类Rust Result类型及and方法类型推断问题排查

复刻Rust Result库时的TypeScript类型错误问题

问题重现

我尝试在TypeScript中复刻Rust的Result库,实现了以下代码:

原实现代码

interface BaseResult<T, E> {
  isOk(): boolean
  isErr(): boolean
  and<U>(res: Result<U, E>): Result<U, E>
}

class ErrImpl<E> implements BaseResult<never, E> {
  readonly val!: E

  constructor(val: E) {
    this.val = val
  }

  isOk(): boolean {
    return false
  }

  isErr(): boolean {
    return true
  }

  and<U>(res: Result<U, E>): Result<U, E> {
    return this
  }
}

class OkImpl<T> implements BaseResult<T, never> {
  readonly val!: T

  constructor(val: T) {
    this.val = val
  }

  isOk(): boolean {
    return true
  }

  isErr(): boolean {
    return false
  }

  and<U, E>(res: Result<U, E>) {
    return res
  }
}

export type Result<T, E> = OkImpl<T> | ErrImpl<E>

测试代码与错误

function alwaysFailsString(): Result<boolean, string> {
  return new ErrImpl("a")
}

let errString1 = alwaysFailsString()
let errString2 = alwaysFailsString()

let v = errString1.and(errString2)

出现类型错误:

This expression is not callable.
Each member of the union type '(<U, E>(res: Result<U, E>) => Result<U, E>) | (<U>(res: Result<U, string>) => Result<U, string>)' has signatures, but none of those signatures are compatible with each other.ts(2349)

我的预期是:and方法遵循Rust的逻辑——若当前是Ok则返回传入的res,若为Err则返回自身,类型上应该返回Result<U, E>。

错误原因

问题出在OkImpl的and方法泛型定义:

  • BaseResult接口中,and方法的泛型仅为<U>,E是当前BaseResult实例的错误类型(对于OkImpl来说,E是never)
  • 但OkImpl中自行添加了泛型<U, E>,这相当于重新声明了一个任意的E类型,覆盖了接口继承的E类型
  • 这导致ErrImpl的and方法签名(固定使用自身的E)和OkImpl的and方法签名(任意E)无法兼容,TypeScript在处理联合类型的方法调用时,要求所有成员的方法签名必须可兼容,因此触发错误。

解决方案

修正OkImpl的and方法,移除多余的泛型参数E,让它遵循BaseResult接口的定义:

class OkImpl<T> implements BaseResult<T, never> {
  readonly val!: T

  constructor(val: T) {
    this.val = val
  }

  isOk(): boolean {
    return true
  }

  isErr(): boolean {
    return false
  }

  // 移除多余的E泛型,使用接口定义的E(即never)
  and<U>(res: Result<U, never>): Result<U, never> {
    return res
  }
}

补充优化(可选)

如果希望OkImpl的and方法能接受任意错误类型的Result(更贴近Rust的行为,因为Rust中Ok的and会保留传入Result的错误类型),可以调整BaseResult的接口定义,让and方法的错误类型可以是原错误类型的超集:

interface BaseResult<T, E> {
  isOk(): boolean
  isErr(): boolean
  // 允许传入的Result错误类型是E的超集,返回的错误类型也对应调整
  and<U, F extends E>(res: Result<U, F>): Result<U, F>
}

class ErrImpl<E> implements BaseResult<never, E> {
  readonly val!: E

  constructor(val: E) {
    this.val = val
  }

  isOk(): boolean {
    return false
  }

  isErr(): boolean {
    return true
  }

  and<U, F extends E>(res: Result<U, F>): Result<U, F> {
    return this
  }
}

class OkImpl<T> implements BaseResult<T, never> {
  readonly val!: T

  constructor(val: T) {
    this.val = val
  }

  isOk(): boolean {
    return true
  }

  isErr(): boolean {
    return false
  }

  and<U, F>(res: Result<U, F>): Result<U, F> {
    return res
  }
}

这样调整后,OkImpl的and方法可以接受任意错误类型的Result,而ErrImpl的and方法仅接受错误类型是自身错误类型超集的Result,完全符合Rust中Result::and的行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 14:57:03