TypeScript中如何指定Generator的next参数类型并保留yield类型推断?
解决生成器指定Next参数类型同时自动推断Yield类型的问题
当你显式指定Generator<unknown, unknown, Next>时,第一个泛型参数被硬编码为unknown,导致后续通过ReturnType提取的产出类型也变成unknown。下面提供几种可行的解决方案,既可以指定.next()的参数类型,又能让TypeScript自动推断生成器的产出类型:
方案1:类型断言指定Next类型(最简洁)
直接通过类型断言告诉TypeScript生成器的Next参数类型,同时保留自动推断的Yield类型:
// 定义你需要的Next参数类型 type Next = "continue" | "stop"; // 生成器函数:用类型断言指定Next类型,Yield类型自动推断 function* lex() { // cmd 的类型自动为 Next const cmd = yield { kind: "number", text: "123" }; if (cmd === "stop") return; yield { kind: "char", text: "x" }; } as Generator<any, void, Next>; // 提取产出类型作为Token type Token = ReturnType<typeof lex> extends Generator<infer T, any, any> ? T : never; // 类型验证 const gen = lex(); gen.next(); // ✅ 返回 { value: { kind: "number", text: "123" }, done: false } gen.next("continue"); // ✅ 返回 { value: { kind: "char", text: "x" }, done: false } gen.next("invalid"); // ❌ TypeScript报错:类型不匹配Next类型
方案2:条件类型验证并提取类型
不修改生成器函数写法,通过类型约束确保Next类型符合要求,同时提取Yield类型:
// 定义你需要的Next参数类型 type Next = { signal: "continue" | "stop" }; // 生成器函数:不指定返回类型,让TypeScript自动推断 function* lex() { const control = yield { kind: "number", text: "123" }; // 手动指定control类型为Next,避免unknown/any const typedControl: Next = control; if (typedControl.signal === "stop") return; yield { kind: "char", text: "x" }; } // 验证生成器的Next类型,不符合则返回never(触发报错) type ValidatedGenerator = ReturnType<typeof lex> extends Generator<infer T, any, Next> ? Generator<T, any, Next> : never; // 提取产出类型作为Token type Token = ValidatedGenerator extends Generator<infer T, any, any> ? T : never; // 使用时需指定实例类型为ValidatedGenerator const gen: ValidatedGenerator = lex(); gen.next({ signal: "continue" }); // ✅ 正确 gen.next({ signal: "invalid" }); // ❌ TypeScript报错
方案3:泛型辅助类型(TypeScript 4.7+)
利用泛型辅助类型封装Next约束,代码更清晰:
type Next = string; // 定义辅助类型:约束生成器的Next参数类型 type GeneratorWithNext<NextType> = Generator<any, unknown, NextType>; // 生成器函数返回辅助类型,Yield类型自动推断 function* lex(): GeneratorWithNext<Next> { const input = yield { kind: "number", text: "123" }; // input 的类型自动为 Next yield { kind: "char", text: input.charAt(0) }; } // 提取产出类型作为Token type Token = ReturnType<typeof lex> extends Generator<infer T, any, any> ? T : never;
内容的提问来源于stack exchange,提问作者Jacob
相关产品推荐
相关产品推荐

