TypeScript如何从带可选属性类型的具体对象中提取实际类型
核心原因
你给DefaultServerNotes和DefaultClientNotes显式标注了Notes类型,TypeScript会执行向上类型转换,丢弃对象字面量的实际结构信息,仅保留通用的Notes类型,因此直接用typeof无法得到你需要的精确结构。
方案1:使用 satisfies 操作符(TS 4.9+ 推荐)
satisfies 操作符可以在不丢失原始类型信息的前提下,校验值是否符合目标类型约束,是目前最优的解法。
type PushTypes = "start" | "finish" type PullTypes = "start" | "stop" interface Notes { push: Partial<Record<PushTypes, boolean>>; pull?: Partial<Record<PullTypes, boolean>>; } // 不用显式加: Notes注解,用satisfies做校验 const DefaultServerNotes = { push: { start: true, finish: true, }, } satisfies Notes; const DefaultClientNotes = { push: { finish: true }, pull: { stop: true }, } satisfies Notes; // 此时typeof就能拿到精确结构类型 type ServerNotes = typeof DefaultServerNotes; // 推导结果: // { // push: { // start: boolean; // finish: boolean; // }; // } type ClientNotes = typeof DefaultClientNotes; // 推导结果: // { // push: { finish: boolean }; // pull: { stop: boolean }; // }
如果你的对象结构不符合Notes约束,TS会直接在satisfies位置抛出错误,不会影响类型安全。
方案2:使用泛型辅助函数(兼容低版本TS)
如果你的TS版本低于4.9无法使用satisfies,可以通过泛型工具函数实现同样的效果:
// 定义泛型辅助函数,入参必须符合Notes约束,同时返回原始参数类型 function defineNotes<T extends Notes>(notes: T): T { return notes; } const DefaultServerNotes = defineNotes({ push: { start: true, finish: true, }, }); const DefaultClientNotes = defineNotes({ push: { finish: true }, pull: { stop: true }, }); // 效果和satisfies完全一致 type ServerNotes = typeof DefaultServerNotes; type ClientNotes = typeof DefaultClientNotes;
内容的提问来源于stack exchange,提问作者Wainage
相关产品推荐
相关产品推荐

