TypeScript中string类型可赋值给{}类型的原因解析——为何相关代码未触发类型错误
const test: {} = "test" valid TypeScript? 这个问题真的很容易踩坑——我刚学TypeScript的时候也被{}类型的真实含义坑过好几次!核心原因是:你对{}类型的理解和TypeScript的实际定义完全不一样。
先搞懂{}类型到底是什么
在TypeScript里,{}不是“空对象”的意思,它代表的是任何非null、非undefined的值。
为什么字符串能赋值给它?因为JavaScript中所有原始类型(string、number、boolean)在需要调用方法时,都会被自动装箱成对应的包装对象(比如String、Number),这些包装对象都继承自Object,拥有toString()、valueOf()等原型方法。而{}类型的约束就是“拥有Object原型上所有方法的值”,所以原始类型自然符合这个要求。
举个直观的例子:
const str: {} = "test"; console.log(str.toString()); // 能正常执行,因为字符串装箱后具备这个方法
这就是TypeScript不会给const test: {} = "test"报错的原因——它认为字符串完全符合{}类型的约束。
你的API参数问题根源
回到你写的这段代码:
const getAPIData = async (id: string, filters: NetworkFilters | {} = {})
这里的| {}相当于把filters的类型放宽到了“NetworkFilters或者任何非空、非undefined的值”,所以当你误传string类型时,TypeScript会认为它是合法的,自然不会触发类型错误。这完全偏离了你“默认是空对象,且只能传NetworkFilters或空对象”的预期。
怎么修复这个问题?
根据你的需求,这里有几种靠谱的解决方案:
1. 用Record<string, never>表示真正的空对象
这个类型专门用来定义“没有任何可枚举属性的对象”,完美匹配你想要的“无属性空对象”:
const getAPIData = async (id: string, filters: NetworkFilters | Record<string, never> = {})
此时如果传入string,TypeScript会直接抛出类型错误:Type 'string' is not assignable to type 'NetworkFilters | Record<string, never>'.
2. 使用小写的object类型
小写的object类型表示所有非原始类型的值(普通对象、数组、函数等),会直接拒绝string、number这类原始类型:
const getAPIData = async (id: string, filters: NetworkFilters | object = {})
不过要注意,它也允许数组、函数等其他对象类型,如果你的NetworkFilters是普通对象,这种方案是可以接受的。
3. 直接省略| {}(如果NetworkFilters支持空对象)
如果NetworkFilters的所有属性都是可选的,那你完全不需要加| {},直接写:
const getAPIData = async (id: string, filters: NetworkFilters = {})
这样既保留了空对象默认值,又确保只能传入符合NetworkFilters类型的值(包括空对象)。
最后再理清楚几个容易混淆的对象类型
为了避免再踩类似的坑,记住这几个TypeScript对象类型的区别:
{}:非null/undefined的任意值(包括原始类型)object:非原始类型的任意对象(数组、函数、普通对象等)Record<string, never>:完全没有属性的空对象{ [key: string]: never }:和Record<string, never>等价,也是严格的空对象
内容的提问来源于stack exchange,提问作者deaponn

