TypeScript如何根据一个参数值推导关联函数参数的正确类型
问题原因
你当前的泛型写法无法自动推导类型,是TypeScript控制流分析的现有特性限制:当两个参数是独立的泛型参数时,TS不会在分支判断中自动关联两个参数的类型关系——即使你判断了type === "book",TS也不会将泛型参数Type收窄为字面量"book",自然也不会把MapTypes[Type]对应收窄为Book类型。
不需要使用类型断言,有两种成熟的零断言方案可以实现自动类型推导:
方案1:将入参重构为带辨识标签的联合元组(推荐)
把两个参数的对应关系封装为联合类型的元组,TS可以通过元组第一个元素的字面量值,自动收窄第二个元素的类型:
interface User { name: string; } interface Book { name: string; author: string; } type MapTypes = { user: User; book: Book; } type TypeName = keyof MapTypes; // 生成联合元组:[type: "user", data: User] | [type: "book", data: Book] type HandlerParams = { [K in TypeName]: [type: K, data: MapTypes[K]] }[TypeName] const handler = (...[type, data]: HandlerParams) => { if (type === "book") { // 此处data自动推导为Book类型,直接访问author无报错 console.log(data.author); } if (type === "user") { // 此处data自动推导为User类型 console.log(data.name); } } // 调用时也会做类型校验,传错data类型会直接报错 handler("book", { name: "三体", author: "刘慈欣" }) // 正常 handler("user", { name: "张三" }) // 正常 handler("book", { name: "张三" }) // 报错,缺少author字段
方案2:使用函数重载
通过函数重载声明不同type参数对应的data类型,实现分支内的自动类型收窄:
interface User { name: string; } interface Book { name: string; author: string; } // 重载签名 function handler(type: "user", data: User): void; function handler(type: "book", data: Book): void; // 实现签名 function handler(type: "user" | "book", data: User | Book) { if (type === "book") { // 此处data自动推导为Book类型 console.log(data.author); } if (type === "user") { // 此处data自动推导为User类型 console.log(data.name); } }
两种方案都不需要任何类型断言,完全依靠TS的类型系统完成自动推导,同时在函数调用时也会做严格的类型校验,避免传参错误。
内容的提问来源于stack exchange,提问作者Michal
相关产品推荐
相关产品推荐

