如何在TypeScript中定义满足另一类型的类型且不生成额外JS代码?
TypeScript 类型层面实现类似
satisfies的约束 TypeScript 4.9推出的satisfies操作符在值处理上非常实用——它允许你用窄类型的变量匹配宽类型的定义,同时保留变量自身的窄类型信息,比如:
type WideType = Record<string, number>; const narrowValues = { hello: 4, world: 5, } satisfies WideType;
这里narrowValues的类型会被推断为{ hello: 4; world: 5 },同时TypeScript会自动校验它是否符合WideType的约束。
但目前satisfies只能用于值,没法直接在类型定义里使用,比如下面的写法会直接报错:
type WideType = Record<string, number>; type NarrowType = { hello: 4, world: 5, } satisfies WideType; // 语法错误:satisfies操作符不能用于类型
现在常用的替代方案是通过值推导类型,但这种方式在复杂场景下会很繁琐,还会生成不必要的JS代码:
type TemplateType = `${number}-${number}`; type UnionType = "FOO" | "BAR"; type WideType = Record<string, string>; // 这个变量会被编译到JS中,但我们其实只需要它的类型 const narrowValues = { hello: "" as TemplateType, world: "" as UnionType, blah: "" as string } satisfies WideType; type NarrowType = typeof narrowValues;
如果想在不生成任何额外JS代码的前提下,实现类型间的满足关系,有两种靠谱的方法:
方法一:用工具类型实现类型约束
定义一个简单的工具类型,通过条件类型强制检查目标类型是否符合宽类型的约束:
type Satisfies<T, U> = T extends U ? T : never; // 使用示例 type WideType = Record<string, number>; // 如果下面的类型不符合WideType,会直接报错 type NarrowType = Satisfies<{ hello: 4, world: 5, }, WideType>;
针对复杂场景的用法:
type TemplateType = `${number}-${number}`; type UnionType = "FOO" | "BAR"; type WideType = Record<string, string>; type NarrowType = Satisfies<{ hello: TemplateType, world: UnionType, blah: string }, WideType>;
这种方式完全在类型层面处理,不会产生任何JS代码,同时能确保NarrowType符合WideType的约束。
方法二:用declare const创建虚拟变量
利用declare const声明一个仅用于类型推导的虚拟变量,它不会被编译到JS代码中,写法也更接近值层面的satisfies:
type TemplateType = `${number}-${number}`; type UnionType = "FOO" | "BAR"; type WideType = Record<string, string>; // declare const 不会生成JS代码 declare const narrowValues: { hello: TemplateType, world: UnionType, blah: string } satisfies WideType; type NarrowType = typeof narrowValues;
这种方式的优势是语法直观,和值层面的satisfies用法几乎一致,同样能实现类型约束且无额外JS代码。
目前TypeScript官方还没有支持直接在类型定义中使用satisfies的计划,但通过上面两种方法,完全可以实现类似的效果。
内容的提问来源于stack exchange,提问作者Sandy Gifford
相关产品推荐
相关产品推荐

