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

TypeScript泛型函数内部返回类型为never的问题求助

问题分析与解决

问题描述

这段TypeScript代码中,getDetails函数内部的两个return语句都会被TypeScript提示返回类型为never,但调用该函数时,返回类型却能被正确推导。代码如下:

enum Partition {
  A = 'A',
  B = 'B',
}

type PartitionDetailsMap = {
  [Partition.A]: null;
  [Partition.B]: {
    [key: string]: {
      id: string;
      name: string;
    };
  };
};

function isA(t): t is Partition.A {
  return true;
}

function isB(t): t is Partition.B {
  return true;
}

function getDetails<T extends Partition>(partition: T): PartitionDetailsMap[T] {
  if (isA(partition)) {
    return null; // 此处提示返回类型应为never
  }
  if (isB(partition)) {
    return {
      '1': { id: '1', name: 'ONE' },
      '2': { id: '2', name: 'TWO' },
    }; // 此处同样提示返回类型应为never
  }
}

const toto: null = getDetails(Partition.A); // 类型推导正确
const tata: { [key: string]: { id: string; name: string } } = getDetails(Partition.B); // 类型推导正确

原因

TypeScript在泛型函数内部,无法将泛型参数T与类型守卫缩小后的具体类型(Partition.A/Partition.B)建立精确关联。虽然类型守卫能确定当前分支中partition的类型,但TS没办法自动推断出当前分支的返回值正好匹配PartitionDetailsMap[T]的类型,因此会判定返回值不符合函数声明的返回类型,最终提示never。

另外,当前的类型守卫函数isA和isB未指定参数类型,也会削弱TS的类型推导能力。

解决办法

方法1:完善类型守卫 + 类型断言

先给类型守卫明确参数类型,再通过类型断言告诉TS当前返回值匹配泛型对应的类型:

enum Partition {
  A = 'A',
  B = 'B',
}

type PartitionDetailsMap = {
  [Partition.A]: null;
  [Partition.B]: {
    [key: string]: {
      id: string;
      name: string;
    };
  };
};

// 明确参数类型为Partition,同时修正判断逻辑(原固定return true不合理)
function isA(t: Partition): t is Partition.A {
  return t === Partition.A;
}

function isB(t: Partition): t is Partition.B {
  return t === Partition.B;
}

function getDetails<T extends Partition>(partition: T): PartitionDetailsMap[T] {
  if (isA(partition)) {
    return null as PartitionDetailsMap[T];
  }
  if (isB(partition)) {
    return {
      '1': { id: '1', name: 'ONE' },
      '2': { id: '2', name: 'TWO' },
    } as PartitionDetailsMap[T];
  }
  // 补充兜底逻辑,避免函数存在无返回的风险
  throw new Error('Invalid partition type');
}

const toto: null = getDetails(Partition.A);
const tata: { [key: string]: { id: string; name: string } } = getDetails(Partition.B);

方法2:使用函数重载替代泛型

函数重载能明确指定每个输入对应的返回类型,TS内部可直接识别分支返回值的匹配性:

enum Partition {
  A = 'A',
  B = 'B',
}

type PartitionDetailsMap = {
  [Partition.A]: null;
  [Partition.B]: {
    [key: string]: {
      id: string;
      name: string;
    };
  };
};

function isA(t: Partition): t is Partition.A {
  return t === Partition.A;
}

function isB(t: Partition): t is Partition.B {
  return t === Partition.B;
}

// 函数重载声明:明确每个输入对应的返回类型
function getDetails(partition: Partition.A): null;
function getDetails(partition: Partition.B): PartitionDetailsMap[Partition.B];
// 函数实现
function getDetails(partition: Partition): PartitionDetailsMap[Partition] {
  if (isA(partition)) {
    return null;
  }
  if (isB(partition)) {
    return {
      '1': { id: '1', name: 'ONE' },
      '2': { id: '2', name: 'TWO' },
    };
  }
  throw new Error('Invalid partition type');
}

const toto: null = getDetails(Partition.A);
const tata: { [key: string]: { id: string; name: string } } = getDetails(Partition.B);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 14:38:25