You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 20:05:39