全栈Tom
1/8/2025
嘿,大家好!👋
我最近在搞一个 TypeScript 项目,结果被一个小问题搞得头大。😅 我想用泛型来定义一个 Example
类,目标是创建一个类型为 Example<{ min: 1 }>
的实例。代码如下:
type Config = { min?: number; max?: number; }; class Example<C extends Config> { example = true; constructor(private config: Readonly<C> = {} as C) {} public min<const N extends number>(min: N) { return new Example<C & { min: N }>({ ...this.config, min, }); } }
我写了个测试函数来验证各种构造类的方式:
const test = (example: Example<{ min: 1 }>) => example;
然后我测试了几种情况:
// 这些应该通过 test(new Example({ min: 1 })); test(new Example().min(1)); test(new Example({}).min(1)); // 这些应该失败 test(new Example({})); test(new Example({ min: 2 })); test(new Example().min(2));
一切正常,直到我试了这个:
test(new Example());
居然没有报错!😱 默认的 {}
居然可以赋值给 { min: 1 }
,这不科学啊!我还试着改了测试函数:
const test = <C extends { min: 1 }>(example: Example<C>) => example;
这样确实报错了,但这不是我想要的解决方案。问题是 new Example()
不应该能赋值给 Example<{ min: 1 }>
。
我试了各种方法,还是没搞定。有没有大佬能帮我看看这个问题?🙏
PS: 我在 TypeScript Playground 上也试过了,结果还是一样。链接在这:Playground
谢谢大家!🙌
程序员小王
1/8/2025
嘿,你好啊!👋 我太理解你遇到的 TypeScript 泛型问题了 - 我之前也栽在这上面!TypeScript 的类型系统有时候会让人抓狂,特别是当你想要严格控制类型时。别担心,我们一起来看看怎么解决这个问题。
你遇到的问题是因为 TypeScript 的类型推断机制。默认情况下,new Example()
会被推断为 Example<{}>
,而 {}
是可以赋值给任何对象类型的,包括 { min: 1 }
。这就是为什么 test(new Example())
没有报错。
为了防止 new Example()
被错误地赋值给 Example<{ min: 1 }>
,我们可以通过在构造函数中添加类型检查来确保 min
属性的存在。你可以使用一个类型断言来强制类型检查。
以下是一个可能的解决方案:
class Example<C extends Config> { example = true; constructor(private config: Readonly<C> = {} as C) { // 检查 config 是否包含 min 属性 if (!('min' in config)) { throw new Error("Config must include a 'min' property"); } } public min<const N extends number>(min: N) { return new Example<C & { min: N }>({ ...this.config, min, }); } }
config
包含 min
属性。如果没有,我们抛出一个错误。这将阻止 new Example()
被错误地使用。希望这能帮到你!如果你还有其他问题,随时问我哦!继续加油,TypeScript 的学习曲线虽然陡峭,但掌握后会让你的代码更健壮!🚀
如果你需要进一步的帮助,随时联系我!🙌