TypeScript联合类型不兼容问题:如何修复RoleEntity赋值错误?
问题描述
我定义了以下联合类型:
type Role = 'x' | 'y' | 'z' | 't' type Entity = { personId: string } | { organizationId: string } type RoleEntity = { role: 'x', personId: string } | { role: 'y', personId: string } | { role: 'z', organizationId: string } | { role: 'y', organizationId: string }
还有一个函数laFunc,用于传入role和entity后将RoleEntity插入数组:
function laFunc(r: Role, entity: Entity) { const nard: RoleEntity[] = [] switch (r) { case 'x': case 'y': { if ('personId' in entity) { nard.push({ role: r, personId: entity.personId }) } } } }
但我遇到了如下错误:
Argument of type '{ role: "x" | "y"; personId: string; }' is not assignable to parameter of type 'RoleEntity'. Type '{ role: "x" | "y"; personId: string; }' is not assignable to type '{ role: "y"; personId: string }'. Types of property 'role' are incompatible. Type '"x" | "y"' is not assignable to type '"y"'. Type '"x"' is not assignable to type '"y"'.(2345)
请问该如何修复这个问题?
问题原因
TypeScript的类型收窄在这里没完全生效:虽然通过switch把r限定为'x' | 'y',但在push时TS无法确定当前r的具体值,推断出的类型是联合类型,而RoleEntity里的role是明确的字面量类型,两者无法匹配。
修复方案
方案1:使用类型断言
直接告诉TS当前对象符合RoleEntity类型,适合快速修复:
function laFunc(r: Role, entity: Entity) { const nard: RoleEntity[] = [] switch (r) { case 'x': case 'y': { if ('personId' in entity) { nard.push({ role: r, personId: entity.personId } as RoleEntity) } break } // 建议补上其他case的默认处理,避免逻辑遗漏 case 'z': case 't': break } }
方案2:拆分case分支,让TS精确收窄类型
把'x'和'y'的case分开写,TS就能明确每个分支里r的具体类型:
function laFunc(r: Role, entity: Entity) { const nard: RoleEntity[] = [] switch (r) { case 'x': { if ('personId' in entity) { nard.push({ role: r, personId: entity.personId }) } break } case 'y': { if ('personId' in entity) { nard.push({ role: r, personId: entity.personId }) } // 补上RoleEntity中y角色对应organizationId的逻辑 if ('organizationId' in entity) { nard.push({ role: r, organizationId: entity.organizationId }) } break } case 'z': { if ('organizationId' in entity) { nard.push({ role: r, organizationId: entity.organizationId }) } break } case 't': // 根据实际需求处理t角色的逻辑 break } }
方案3:重构类型,让TS自动关联映射
通过映射类型重新定义RoleEntity,避免手动维护联合类型的遗漏,同时让函数参数类型自动关联:
type Role = 'x' | 'y' | 'z' | 't' // 定义角色与对应实体类型的映射 type RoleToEntity = { x: { personId: string }, y: { personId: string } | { organizationId: string }, z: { organizationId: string }, t: never // 根据实际业务定义t对应的实体类型 } // 自动生成RoleEntity类型 type RoleEntity = { [K in keyof RoleToEntity]: { role: K } & RoleToEntity[K] }[keyof RoleToEntity] function laFunc<K extends Role>(r: K, entity: RoleToEntity[K]) { const nard: RoleEntity[] = [] nard.push({ role: r, ...entity }) }
这种方式更健壮,传参时如果角色与实体类型不匹配,TS会直接抛出错误。
内容的提问来源于stack exchange,提问作者stalin
相关产品推荐
相关产品推荐

