TypeScript开发算术程序时如何检查泛型类型参数T的类型避免0值错误
问题解答
核心结论
TypeScript 是纯静态类型语言,所有泛型、类型约束相关的信息都会在编译阶段完全擦除,运行时不存在泛型参数T的实体,因此你无法直接在运行时检查T的取值来触发报错。
可行解决方案
可以从编译期静态校验 + 运行时动态兜底两个维度结合处理你的需求:
1. 编译期类型收紧(优先)
你可以通过条件类型强化Pow类的泛型约束,在代码编写阶段就拦截非法场景:
type PowReturn<A extends number, N extends number> = N extends 1 ? A : A extends 0 ? 0 : number class Pow<A extends number, N extends number, T = PowReturn<A,N>> extends Calcul<T extends number ? T : never> { constructor(public a: Calcul<A>, public n: Calcul<N>) { super() } // 原有逻辑 }
这样当你实例化Pow时,如果出现A=0且返回值要求为noZero的情况,编译阶段就会直接报错,无需等到运行时。
2. 运行时校验兜底
针对存在变量、编译期无法确定值的场景,你可以给Calcul基类增加运行时可调用的校验方法,统一处理类型合规性检查:
abstract class Calcul<T extends number> { // 新增运行时校验方法,判断输入值是否符合当前实例的类型约束 abstract validateValue(val: number): val is T // 原有resolve等逻辑 } // 具体实现示例:0值类型的Calcul class ZeroCalcul extends Calcul<0> { validateValue(val: number): val is 0 { return val === 0 } } // 非0值类型的Calcul class NonZeroCalcul extends Calcul<noZero> { validateValue(val: number): val is noZero { return val !== 0 } }
然后修改你的Pow.resolve逻辑:
resolve(variable?: Variable<T>): Calcul<T> | T { if (this.n.resolve() === 1) { const aRes = this.a.resolve() // 若a已经是具体数值,先做合法性校验 if (typeof aRes === 'number') { if (!this.validateValue(aRes)) { throw new Error('非法计算结果:预期非0值,实际得到0') } return aRes as T } return this.a as Calcul<T> } // 其他原有逻辑 }
3. Branded Type 强化 runtime 安全
你可以给noZero类型增加运行时标记,确保所有noZero类型的实例在创建时就已经过校验,从源头避免0值混入:
declare const __nonZero: unique symbol type noZero = number & { [__nonZero]: true } // 工具函数创建noZero类型值,创建时自动校验 function createNonZero(val: number): noZero { if (val === 0) throw new Error('不能创建值为0的noZero类型') return val as noZero }
内容的提问来源于stack exchange,提问作者Rémi Bernard
相关产品推荐
相关产品推荐

