如何在TypeScript中显式变更变量的控制流类型?
问题描述
我了解可以使用as关键字在需要的位置做内联类型断言,但我想要实现的是在代码块内变更变量的类型,让这个类型持续生效到代码块结束。希望在不创建单独变量、且理想情况下不使用运行时断言的前提下完成这件事。
需求总结
- 不使用
as关键字进行类型断言 - 不创建单独变量
- 无运行时断言
示例场景
我尝试编写一个setProp方法,通过单个函数设置对象的属性。这个函数用泛型来确保属性和对应值的类型匹配。函数内部有一个大型switch语句,分别处理每个属性,而且每个属性可能需要多次访问传入的value(所以不想用as断言,否则会产生重复代码)。
更理想的情况是TypeScript能在switch分支里自动推断value的类型,但我觉得目前做不到。
下面是简化后的示例代码:
interface Props { name: string; age: number; enrolled: boolean; } const props: Props = { name: '', age: 0, enrolled: false, }; export function setProp<K extends keyof Props>(prop: K, value: Props[K]): void { const propName: keyof Props = prop; // 必须这么写,因为TypeScript没法拆解K类型里的联合类型 switch (propName) { case 'name': props.name = value; // ^-- 报错! // Type 'string | number | boolean' is not assignable to type 'string'. // Type 'number' is not assignable to type 'string'.(2322) break; case 'age': props.age = value; // ^-- 同样报错! break; case 'enrolled': props.enrolled = value; // ^-- 同样报错! break; } } // 调用时TypeScript会强制检查属性名和值的类型组合 setProp('name', 'John'); setProp('age', 20); setProp('enrolled', true);
接近可行的方案
我想到的最接近需求的方案是用一个完全没有运行时检查的断言函数,依赖主流打包工具的树摇/死代码消除功能把它移除:
export function uncheckedAssert<T>(value: unknown): asserts value is T { return; }
修改后的setProp函数如下:
export function setProp<K extends keyof Props>(prop: K, value: Props[K]): void { const propName: keyof Props = prop; // 必须这么写,因为TypeScript没法拆解K类型里的联合类型 switch (propName) { case 'name': uncheckedAssert<Props[typeof propName]>(value); props.name = value; // ^-- 不再报错! break; case 'age': uncheckedAssert<Props[typeof propName]>(value); props.age = value; // ^-- 不再报错! break; case 'enrolled': uncheckedAssert<Props[typeof propName]>(value); props.enrolled = value; // ^-- 不再报错! break; } }
内容的提问来源于stack exchange,提问作者Frank Weindel
相关产品推荐
相关产品推荐

