TypeScript编译前校验函数参数:限制receiveOnEdge的edgeId取值
实现自定义边缘ID的静态类型检查
要让编辑器在传入非法边缘ID时即时提示,核心是利用TypeScript的泛型字面量类型推断,把模块的输入边缘ID集合绑定到类实例的类型上,从而约束方法参数的合法值。具体实现如下:
用泛型绑定合法ID集合
将Package类定义为泛型类,泛型参数EdgeId用来存储当前模块允许的边缘ID联合类型。这样recieveOnEdge方法的edgeId参数会被严格约束为该集合内的值,编辑器自动拦截非法输入。初始化时自动推断ID类型
init方法通过泛型参数NewEdgeId,从传入的模块中自动推断出输入边缘ID的字面量联合类型,并返回类型更具体的Package实例,让后续方法调用具备类型检查能力。补充运行时校验
静态类型检查能在编辑器阶段拦截大多数错误,但为了防止类型断言等方式绕过检查,在recieveOnEdge内添加运行时校验,确保实际执行时也能抛出明确错误。
完整代码示例
interface IEdge<Id extends string = string> { id: Id } interface IModule<EdgeId extends string = string> { id: string data: { inputEdges: IEdge<EdgeId>[] } } class Package<EdgeId extends string = never> { module: IModule<EdgeId> | null = null init<NewEdgeId extends string>(module: IModule<NewEdgeId>): Package<NewEdgeId> { this.module = module as IModule<EdgeId> return this as unknown as Package<NewEdgeId> } recieveOnEdge(edgeId: EdgeId, callback: any) { // 运行时校验,避免静态类型被绕过 if (!this.module?.data.inputEdges.some(edge => edge.id === edgeId)) { throw new Error(`边缘ID "${edgeId}" 不存在于当前模块的输入边缘列表中`) } console.log(edgeId, callback) } } // 使用satisfies确保结构合规,同时保留ID的字面量类型 const sampleModule = { id: "sampleModule", data: { inputEdges: [ { id: "sampleEdge" }, { id: "anotherEdge" } ] } satisfies IModule } const packageInstance = new Package().init(sampleModule) packageInstance.recieveOnEdge("sampleEdge", "doesNotMatter") // 合法,无提示 packageInstance.recieveOnEdge("invalidEdge", "doesNotMatter") // 编辑器会提示类型错误
关键细节说明
satisfies关键字确保sampleModule符合IModule接口结构,但不会把ID类型拓宽为string,而是保留具体的字面量联合类型"sampleEdge" | "anotherEdge"。- 泛型默认值
never的作用是:在调用init之前如果调用recieveOnEdge,会因为edgeId要求是never类型而直接报错,强制开发者先完成模块初始化。
内容的提问来源于stack exchange,提问作者MalwareMoon
相关产品推荐
相关产品推荐

