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

TypeScript中无法对继承联合类型的泛型进行类型收窄

问题原因

TypeScript 目前无法将泛型的类型收窄结果和返回值中的条件类型(Extract/Exclude)做关联推导。你已经通过block.type === 'bulleted-list-item'明确了当前block的类型,但TS不会自动推导此时泛型B一定匹配Extract<B, BulletedListItemBlocklike>的约束,因此返回值会报类型不匹配的错误。

解决方案

方案1:使用函数重载(推荐,完全类型安全)

用重载声明对外暴露类型约束,内部直接用联合类型收窄即可,同时保证外部调用和内部逻辑的类型安全:

type ParagraphBlocklike = {
  type: 'paragraph';
};

type BulletedListItemBlocklike = {
  type: 'bulleted-list-item';
};

type Blocklike =
  | ParagraphBlocklike
  | BulletedListItemBlocklike
;

type BulletedListRenderNode<B extends BulletedListItemBlocklike> = {
  type: 'bulleted-list';
  items: B[]
};

type RenderNode<B extends Blocklike> =
  | (Exclude<B, BulletedListItemBlocklike>)
  | BulletedListRenderNode<Extract<B, BulletedListItemBlocklike>>;

// 重载签名,匹配不同入参的返回类型
function fnConvert<B extends ParagraphBlocklike>(block: B): B
function fnConvert<B extends BulletedListItemBlocklike>(block: B): BulletedListRenderNode<B>
function fnConvert(block: Blocklike): RenderNode<Blocklike> {
  if(block.type === 'bulleted-list-item') {
    return {type: 'bulleted-list', items: [block]};
  }
  return block;
}

方案2:最小粒度类型断言

如果需要保留原泛型写法,可以只对返回的对应值做断言,不会影响函数内部其他逻辑的类型安全:

const fnConvert = <B extends Blocklike>(block: B): RenderNode<B> => {
  if(block.type === 'bulleted-list-item') {
    // 此处断言完全符合类型收窄结果,无实际安全风险
    return {type: 'bulleted-list', items: [block as Extract<B, BulletedListItemBlocklike>]};
  }
  return block as Exclude<B, BulletedListItemBlocklike>;
};

两种方案都可以正常使用,外部调用时都会正确返回对应的类型,不会丢失类型安全。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 03:24:04