TypeScript中Readonly<T> & T的含义及Vue3源码使用疑问
Vue 3 源码中
Readonly<T> & T 写法的原因 先看这段Vue 3的类型工具代码:
export type StrictUnwrapSlotsType< S extends SlotsType, T = NonNullable<S[typeof SlotSymbol]>, > = [keyof S] extends [never] ? Slots : Readonly<T> & T
你提到的示例存在一个误区——Readonly<User> & User和User的类型并非完全一致。实际在TypeScript中,前者会将所有属性标记为只读:
interface User { name: string, age: number } type intersectionUser = Readonly<User> & User const user: intersectionUser = { name: "Alice", age: 25 } user.name = "Bob" // ❌ TypeScript报错:无法分配到 "name" ,因为它是只读属性
而直接使用User类型时,属性可以正常修改。
回到Vue的场景,StrictUnwrapSlotsType是处理插槽类型的工具,Vue的设计逻辑里,插槽对象是只读的——组件不应该修改传入的插槽内容。这里用Readonly<T> & T而非直接T,主要有这些原因:
- 强制只读约束:通过交集写法,把
T的所有属性(包括嵌套属性、索引签名)都标记为只读,确保使用该类型的代码无法修改插槽内容,契合Vue的设计意图。 - 结构类型兼容:TypeScript的结构类型系统允许把普通
T类型的值赋值给Readonly<T> & T(结构兼容),但反过来不行,形成了单向的类型安全屏障。 - 覆盖复杂类型场景:当
T包含索引签名、可选属性时,Readonly<T> & T能确保所有层级的属性都被设为只读,而直接T做不到这一点。比如带有索引签名的插槽类型:type SlotObj = { [key: string]: () => VNode } type StrictSlot = Readonly<SlotObj> & SlotObj const slots: StrictSlot = { default: () => h('div') } slots.default = () => h('p') // ❌ 报错:索引签名仅允许读取
这种写法既保留了T的原始结构,又通过类型交集强化了不可变性,是Vue在类型层面保障插槽安全的设计手段。
内容的提问来源于stack exchange,提问作者fiveyi li
相关产品推荐
相关产品推荐

