TypeScript联合类型不匹配:Repository<R>|Repository<V>无法赋值给Repository<V>
问题:TypeScript无法关联Repository与对应PaginateConfig的类型匹配
抽象类定义
export abstract class RepositoryPaginationSwitcher<R, V> { business(businessType: BusinessType): Repository<R> | Repository<V>; business( businessType: BusinessType, paginate?: boolean, ): RepositoryAndPagination<R> | RepositoryAndPagination<V>; business( businessType: BusinessType, paginate?: boolean, ): | (RepositoryAndPagination<R> | RepositoryAndPagination<V>) | (Repository<R> | Repository<V>) { const repository = super.business(businessType); if (!paginate) { return repository; } const segment = businessToSegmentMap.get(businessType); const pagination = this.getPagination()[segment]; return { repository, pagination, }; } }
相关类型定义
// library types export interface ObjectLiteral { [key: string]: any; } type Repository<T extends ObjectLiteral> = { obj: T; } type PaginateConfig<T> = { columns: { [Key in keyof T]: boolean }; } // my types enum BusinessType { REALTY = 'REALTY', VEHICLE = 'VEHICLE' } export type RepositoryAndPagination<E> = { repository: Repository<E>; pagination: PaginateConfig<E>; }; declare function getRepo<R, V>( businessType: BusinessType ): Repository<R> | Repository<V>; declare function getPagination<R, V>( businessType: BusinessType ): PaginateConfig<R> | PaginateConfig<V>;
类型错误信息
libs/core/src/common/base/repository-pagination-switcher.ts:41:7 - error TS2322: Type 'Repository<R> | Repository<V>' is not assignable to type 'Repository<V>'. Type 'Repository<R>' is not assignable to type 'Repository<V>'. Types of property 'target' are incompatible. Type 'EntityTarget<R>' is not assignable to type 'EntityTarget<V>'. Type 'EntitySchema<R>' is not assignable to type 'EntityTarget<V>'. Type 'EntitySchema<R>' is not assignable to type 'EntitySchema<V>'. The types of 'options.columns' are incompatible between these types. Type '{ [P in keyof R]?: EntitySchemaColumnOptions; }' is not assignable to type '{ [P in keyof V]?: EntitySchemaColumnOptions; }'. Type 'keyof V' is not assignable to type 'keyof R'. Type 'string | number | symbol' is not assignable to type 'keyof R'. Type 'string' is not assignable to type 'keyof R'. 41 repository, ~~~~~~~~~~ libs/core/src/common/base/repository-pagination-switcher.ts:42:7 - error TS2322: Type 'PaginateConfig<R> | PaginateConfig<V>' is not assignable to type 'PaginateConfig<V>'. Type 'PaginateConfig<R>' is not assignable to type 'PaginateConfig<V>'. Types of property 'relations' are incompatible. Type 'Extract<R extends Record<string, any> ? { [K in keyof R]-?: K extends string ? R[K] extends Date ? `${K}` : R[K] extends (infer U)[] ? `${K}` | Join<K, U extends Record<...> ? { [K in keyof U]-?: K extends string ? U[K] extends Date ? `${K}` : U[K] extends (infer U)[] ? `${K}` | Join<...> : `${K}` | Join<...> : neve...' is not assignable to type 'Extract<V extends Record<string, any> ? { [K in keyof V]-?: K extends string ? V[K] extends Date ? `${K}` : V[K] extends (infer U)[] ? `${K}` | Join<K, U extends Record<...> ? { [K in keyof U]-?: K extends string ? U[K] extends Date ? `${K}` : U[K] extends (infer U)[] ? `${K}` | Join<...> : `${K}` | Join<...> : neve...'. Type 'Extract<R extends Record<string, any> ? { [K in keyof R]-?: K extends string ? R[K] extends Date ? `${K}` : R[K] extends (infer U)[] ? `${K}` | Join<K, U extends Record<...> ? { [K in keyof U]-?: K extends string ? U[K] extends Date ? `${K}` : U[K] extends (infer U)[] ? `${K}` | Join<...> : `${K}` | Join<...> : neve...' is not assignable to type 'Extract<V extends Record<string, any> ? { [K in keyof V]-?: K extends string ? V[K] extends Date ? `${K}` : V[K] extends (infer U)[] ? `${K}` | Join<K, U extends Record<...> ? { [K in keyof U]-?: K extends string ? U[K] extends Date ? `${K}` : U[K] extends (infer U)[] ? `${K}` | Join<...> : `${K}` | Join<...> : neve...'. Type '{ [K in R extends Record<string, any> ? { [K in keyof R]-?: K extends string ? R[K] extends Date ? `${K}` : R[K] extends (infer U)[] ? `${K}` | Join<K, U extends Record<...> ? { [K in keyof U]-?: K extends string ? U[K] extends Date ? `${K}` : U[K] extends (infer U)[] ? `${K}` | Join<...> : `${K}` | Join<...> : neve...' is not assignable to type 'Extract<V extends Record<string, any> ? { [K in keyof V]-?: K extends string ? V[K] extends Date ? `${K}` : V[K] extends (infer U)[] ? `${K}` | Join<K, U extends Record<...> ? { [K in keyof U]-?: K extends string ? U[K] extends Date ? `${K}` : U[K] extends (infer U)[] ? `${K}` | Join<...> : `${K}` | Join<...> : neve...'. 42 pagination, ~~~~~~~~~~
问题描述
无法让TypeScript识别repository和pagination分别对应Repository<R>/Repository<V>和PaginateConfig<R>/PaginateConfig<V>的类型匹配,尝试改为RepositoryAndPagination<R | V>后依旧报错。
解决方案
问题核心在于TypeScript无法跟踪businessType与R/V类型的关联关系,以下两种方式可解决:
方式一:类型守卫+类型断言
通过明确businessType对应的类型分支,让TS正确关联两个值的类型:
export abstract class RepositoryPaginationSwitcher<R, V> { business(businessType: BusinessType): Repository<R> | Repository<V>; business( businessType: BusinessType, paginate?: boolean, ): RepositoryAndPagination<R> | RepositoryAndPagination<V>; business( businessType: BusinessType, paginate?: boolean, ): | RepositoryAndPagination<R> | RepositoryAndPagination<V> | Repository<R> | Repository<V> { const repository = super.business(businessType); if (!paginate) { return repository; } const segment = businessToSegmentMap.get(businessType); const pagination = this.getPagination()[segment]; if (businessType === BusinessType.REALTY) { return { repository: repository as Repository<R>, pagination: pagination as PaginateConfig<R>, } as RepositoryAndPagination<R>; } else { return { repository: repository as Repository<V>, pagination: pagination as PaginateConfig<V>, } as RepositoryAndPagination<V>; } } }
方式二:基于业务类型的映射类型
重构为映射类型,明确每个BusinessType对应的实体类型,让TS自动推导:
// 替换为实际的实体类型 type RealtyEntity = { id: number; address: string }; type VehicleEntity = { id: number; brand: string }; // 定义业务类型到实体类型的映射 type BusinessEntityMap = { [BusinessType.REALTY]: RealtyEntity; [BusinessType.VEHICLE]: VehicleEntity; }; export abstract class RepositoryPaginationSwitcher { business<T extends BusinessType>(businessType: T): Repository<BusinessEntityMap[T]>; business<T extends BusinessType>( businessType: T, paginate: true, ): RepositoryAndPagination<BusinessEntityMap[T]>; business<T extends BusinessType>( businessType: T, paginate?: boolean, ): Repository<BusinessEntityMap[T]> | RepositoryAndPagination<BusinessEntityMap[T]> { const repository = super.business(businessType) as Repository<BusinessEntityMap[T]>; if (!paginate) { return repository; } const segment = businessToSegmentMap.get(businessType); const pagination = this.getPagination()[segment] as PaginateConfig<BusinessEntityMap[T]>; return { repository, pagination, }; } }
这种方式更直观,避免了泛型参数混乱的问题。
内容的提问来源于stack exchange,提问作者Allan
相关产品推荐
相关产品推荐

