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

自定义TypeScript泛型在两种场景下表现不一致,求协助

问题分析与修复方案

问题根源

你的PathsConditional泛型在处理可选属性和联合条件类型时存在逻辑漏洞:

  1. 可选属性(比如allowedOwners?: Owner[])的类型是Owner[] | undefined,原代码中T extends C的判断会因为undefined不属于Owner | Owner[]联合类型,导致跳过匹配分支,进入数组/对象递归逻辑。
  2. 当条件C是联合类型时,未正确处理T的非undefined部分是否属于联合中的任意类型。

修复后的代码

type Previous = [never, 0, 1, 2, 3, 4, 5, ...0[]];
export type DotPrefix<T extends string> = T extends "" ? "" : `.${T}`;

type PathsConditional<T, C, D extends number = 4> = [D] extends [never]
  ? never
  : (
      // 处理可选属性的undefined情况,直接跳过进入后续分支
      T extends undefined ? never :
      // 忽略undefined,检查实际类型是否属于条件C
      NonNullable<T> extends C
        ? ""
        : T extends Array<infer E>
        ? NonNullable<E> extends C
          ? `${number}`
          : `${number}.${PathsConditional<E, C, Previous[D]>}`
        : T extends object
        ? {
            [K in Exclude<keyof T, symbol>]: `${K}${DotPrefix<
              PathsConditional<T[K], C, Previous[D]>
            >}`;
          }[Exclude<keyof T, symbol>]
        : never
    ) extends infer D
  ? Extract<D, string>
  : never;

type AllowedNames<Base extends object, _Condition> = PathsConditional<
  Base,
  _Condition
>;

// 接口定义保持不变
export interface PrivateStaff {
  id: string;
  firstName: string;
  lastName: string;
  username: string;
  password?: string;
  roleId: number;
  createdAt: string;
  updatedAt: string;
  allowedOwners?: Owner[];
  allowedOwnerIds?: string[];
}

export interface Owner {
  id?: string;
  name?: string;
  allowedModels?: Model[];
  allowedModelIds?: string[];
  allowedYears?: number[];
  allowedMaxOdometer?: number;
  createdAt?: string;
  updatedAt?: string;
}

export interface Model {
  id?: number;
  ownerId?: string;
  verifiedAt?: string;
  makeId?: number;
  collectionId?: number;
  vehicleBodyTypeId?: number;
  engine?: string;
  name?: string;
  description?: string;
  descriptionLong?: string;
  tags?: string;
  seatQty?: number;
  tankSize?: number;
  comingSoon?: boolean;
  owner?: Owner;
  years?: number[];
  colors?: string[];
}

// 现在两个赋值均能正常通过类型检查
const dataKey1: AllowedNames<PrivateStaff, Owner | Owner[]> = "allowedOwners";
const dataKey2: AllowedNames<Owner, Model | Model[]> = "allowedModels";

关键修改点说明

  1. 新增undefined处理分支:T extends undefined ? never : ...,避免可选属性的undefined类型干扰后续类型推导。
  2. 替换类型匹配逻辑:用NonNullable<T> extends C替代原T extends C,忽略undefined的影响,只检查属性的实际值类型是否符合条件。
  3. 数组元素的非空检查:在数组分支中同样使用NonNullable<E> extends C,确保数组元素的类型判断不受可选属性影响。

内容的提问来源于stack exchange,提问作者Mümin Celal Pinar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 00:55:01