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

TypeScript判别联合类型与泛型兼容问题及优化方案咨询

问题:TypeScript Result类型复用ok/err函数时的类型不兼容问题

背景代码

我使用TypeScript 5.4.5,定义了以下工具类型与函数:

type Result<T, E> = [T, null] | [null, E];

function ok<T>(good: T): Result<T, null> {
    return [good, null];
}

function err<E>(bad: E): Result<null, E> {
    return [null, bad];
}

有一个使用Result类型处理fetch响应的工具函数可正常编译:

type FetchResult = Result<Response, Error>;
async function tryFetch(fetch: () => Promise<Response>): Promise<FetchResult> {
    try {
        const result = await fetch();
        if (!result.ok) {
            return [null, new Error(`Failed to fetch: ${result.statusText}`)];
        }
        return [result, null];
    } catch (error) {
        return [null, error as Error];
    }
}

但复用该类型系统的tryFetchJson函数出现TypeScript错误:

type FetchJsonResult<T> = Result<T, Error>;
async function tryFetchJson<T>(fetchFn: () => Promise<Response>): Promise<FetchJsonResult<T>> {
    try {
        const response = await fetchFn();
        if (!response.ok) {
            return err(new Error(`Failed to fetch: ${response.statusText}`));
        }
        const data: T = await response.json();
        return ok(data);
    } catch (error) {
        return err(error as Error);
    }
}

错误信息

类型 'Result<null, Error>' 无法赋值给类型 'FetchJsonResult<T>'。
  类型 '[null, null]' 无法赋值给类型 'FetchJsonResult<T>'。
    类型 '[null, null]' 无法赋值给类型 '[T, null]'。
      源类型第0位与目标类型第0位不兼容。
        类型 'null' 无法赋值给类型 'T'。
          'T' 可被实例化为任意与 'null' 无关的类型。
类型 'Result<T, null>' 无法赋值给类型 'FetchJsonResult<T>'。
  类型 '[null, null]' 无法赋值给类型 'FetchJsonResult<T>'。
类型 'Result<null, Error>' 无法赋值给类型 'FetchJsonResult<T>'。

解决方案

问题根源在于ok和err函数返回的是整个Result联合类型,包含了不符合目标类型的分支(比如ok返回的Result<T, null>包含[null, null]分支,而FetchJsonResult<T>的错误分支是[null, Error])。只需修改ok和err函数,让它们返回具体的元组分支而非整个联合类型,就能让TypeScript正确识别返回值匹配目标类型:

type Result<T, E> = [T, null] | [null, E];

// 修改为返回具体的成功元组分支
function ok<T>(good: T): [T, null] {
    return [good, null];
}

// 修改为返回具体的错误元组分支
function err<E>(bad: E): [null, E] {
    return [null, bad];
}

修改后,tryFetchJson函数无需任何类型断言即可正常编译:

  • ok(data)返回的[T, null]是FetchJsonResult<T>的合法分支
  • err(...)返回的[null, Error]也是FetchJsonResult<T>的合法分支

TypeScript能直接确认这两个返回值都属于目标联合类型的一部分,因此不会再抛出类型不兼容错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 20:03:15