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

TypeScript创建SubThing类型守卫报错的原因与解决方法

TypeScript泛型类型守卫报错:SubThing无法赋值给TThing的解决方案

错误原因

你写的泛型类型守卫中,TThing被约束为Thing的任意子类型(比如Thing<2>、Thing<3>这类具体类型)。而TypeScript对类型守卫有严格规则:类型断言的目标类型必须是参数类型的子类型。当TThing是Thing<2>时,SubThing(即Thing<1>)和它完全不兼容,因此TypeScript抛出错误。

解决方案

方案1:移除泛型参数(最简单实现)

直接将参数类型设为Thing(默认等价于Thing<number>),此时SubThing是Thing的子类型,断言合法:

interface Thing<T extends number = number> {
  one: T;
  two: number;
}

type SubThing = Thing<1>;

const isSubThing = (thing: Thing): thing is SubThing =>
  thing.one === 1;

// 使用示例
const example: Thing = { one: 1, two: 100 };
if (isSubThing(example)) {
  example.one; // 类型收窄为1
}

方案2:泛型兼容的类型守卫(保留灵活性)

如果需要支持传入更具体的Thing子类型,可以通过交集类型或条件类型实现精准收窄:

交集类型版本

const isSubThing = <TThing extends Thing>(thing: TThing): thing is TThing & SubThing =>
  thing.one === 1;

// 使用示例
const testThing: Thing<1 | 2> = { one: 1, two: 2 };
if (isSubThing(testThing)) {
  testThing.one; // 类型收窄为1
}

条件类型版本(更精准)

利用Extract类型从泛型T中提取1,实现更严格的类型收窄:

const isSubThing = <T extends number>(thing: Thing<T>): thing is Thing<Extract<T, 1>> =>
  thing.one === 1;

// 使用示例
const thingA: Thing<1 | 3> = { one: 1, two: 5 };
if (isSubThing(thingA)) {
  thingA.one; // 类型为1
}

const thingB: Thing<2> = { one: 2, two: 3 };
if (isSubThing(thingB)) {
  // TypeScript能识别此分支不可能执行
}

总结

类型守卫的核心要求是断言类型必须是参数类型的子类型,你之前的泛型写法打破了这个规则。通过移除泛型或调整断言类型为交集/条件类型,既能满足TypeScript的类型检查,又能实现基于one属性值的类型收窄需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 02:00:09