TypeScript中如何根据嵌套Input类型定义正确的Output泛型?
问题原因分析
你遇到的output.hello类型为never的问题,核心在于两个点:
类型拓宽导致的模糊性
当你显式把input声明为Input类型时,TypeScript会将每个属性的类型自动拓宽为Property | Input联合类型,而非具体的{ type: "string" }或嵌套Input结构。这种模糊的联合类型无法匹配Output<T>中的任何条件分支,最终落到never。条件判断逻辑的覆盖不足
原Output类型的条件判断顺序和逻辑,没有正确处理Property | Input这种联合类型:T[Key] extends { type: "string" }:因为联合类型包含无type字段的Input,条件不成立;T[Key] extends { type: "number" }:同理,联合类型包含Input,条件不成立;T[Key] extends Input:联合类型包含有type字段的Property,条件也不成立;
最终所有分支都不匹配,返回never。
解决方案
方案1:保留具体类型推断,约束结构而非直接声明类型
去掉input的Input类型声明,用satisfies关键字确保结构符合Input规范的同时,让TypeScript保留每个属性的具体类型信息:
export type Property = { type: "string" } | { type: "number" }; export type Input = { [key: string]: Property | Input }; export type Output<T extends Input> = { [Key in keyof T]: T[Key] extends Property ? T[Key]["type"] extends "string" ? string : number : T[Key] extends Input ? Output<T[Key]> : never }; // 用satisfies约束结构,保留具体类型推断 const input = { hello: { type: "string", }, first: { second: { type: "number" } } } satisfies Input; function processInput<T extends Input>(input: T): Output<T> { const result: Record<string, any> = {}; for (const key in input) { const val = input[key]; if ("type" in val) { result[key] = val.type === "string" ? "" : 0; // 示例赋值逻辑 } else { result[key] = processInput(val); } } return result as Output<T>; } const output = processInput(input); console.log(output.hello); // 类型为string,正常访问 console.log(output.first.second); // 类型为number,正常访问
方案2:调整Output类型的判断逻辑
修改Output类型,优先判断是否为Property类型(通过type字段区分),再处理嵌套的Input结构,确保联合类型能被正确分配:
export type Property = { type: "string" } | { type: "number" }; export type Input = { [key: string]: Property | Input }; // 先判断是否为Property,再处理嵌套Input export type Output<T extends Input> = { [Key in keyof T]: T[Key] extends { type: infer U } ? U extends "string" ? string : number : T[Key] extends Input ? Output<T[Key]> : never };
这种写法通过infer U提取type字段的具体值,能更精准地匹配联合类型中的分支。
内容的提问来源于stack exchange,提问作者pastel-bucket
相关产品推荐
相关产品推荐

