如何通过泛型参数在Flow中移除类型属性?
如何在Flow中通过泛型参数移除Exact Object的属性?
好问题!首先明确一点:你没法通过传入void这类参数直接移除Exact Object里的属性——Flow的Exact类型(用{| ... |}定义的结构)是严格校验所有声明属性的,哪怕属性类型是void,也要求你显式写出这个属性并赋值为undefined,不能直接省略。这就是为什么你写const a: T<void> = {}会报错,必须加上p: undefined才行。
不过针对你提到的Redux Action场景,我们有更优雅的解决方案,能让同一个泛型类型根据参数动态决定是否包含某个属性,完全符合“要么始终携带,要么完全没有”的需求。
解决方案:使用条件类型动态生成结构
Flow支持条件类型(Conditional Types),可以根据泛型参数的类型来选择不同的结构定义。我们可以用这个特性来实现你的需求:
// 定义泛型Action类型,根据M的类型决定是否包含meta属性 type Action<T: string, P, M> = M extends void ? {| type: T, payload: P |} // 当M为void时,只保留type和payload : {| type: T, payload: P, meta: M |}; // 否则包含所有三个属性
测试一下效果
// 不含meta的Action类型 type NoMetaAction = Action<'NO_META', { data: string }, void>; const validNoMeta: NoMetaAction = { type: 'NO_META', payload: { data: 'test' } }; // ✅ 正常通过 const invalidNoMeta: NoMetaAction = { type: 'NO_META', payload: { data: 'test' }, meta: undefined }; // ❌ 报错(类型中没有meta属性) // 包含meta的Action类型 type WithMetaAction = Action<'WITH_META', { id: number }, { trace: string }>; const validWithMeta: WithMetaAction = { type: 'WITH_META', payload: { id: 123 }, meta: { trace: 'abc' } }; // ✅ 正常通过 const invalidWithMeta: WithMetaAction = { type: 'WITH_META', payload: { id: 123 } }; // ❌ 报错(缺少meta属性)
这个方案完美满足你的需求:当你传入void作为第三个参数时,生成的类型完全没有meta属性;传入其他类型时,meta属性是必填的,不存在“可选”的中间状态。
为什么void不能直接移除属性?
再补充解释一下核心原因:Flow的Exact类型设计就是为了严格匹配结构——声明了的属性必须存在,未声明的属性不能添加。void类型在这里只是指定了属性的取值只能是undefined,但并没有改变“属性必须存在”的规则。所以T<void>依然是{| p: void |},要求必须有p属性,值为undefined。
内容的提问来源于stack exchange,提问作者Philipp Dargel
相关产品推荐
相关产品推荐

