自定义TypeScript泛型在两种场景下表现不一致,求协助
问题分析与修复方案
问题根源
你的PathsConditional泛型在处理可选属性和联合条件类型时存在逻辑漏洞:
- 可选属性(比如
allowedOwners?: Owner[])的类型是Owner[] | undefined,原代码中T extends C的判断会因为undefined不属于Owner | Owner[]联合类型,导致跳过匹配分支,进入数组/对象递归逻辑。 - 当条件
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";
关键修改点说明
- 新增
undefined处理分支:T extends undefined ? never : ...,避免可选属性的undefined类型干扰后续类型推导。 - 替换类型匹配逻辑:用
NonNullable<T> extends C替代原T extends C,忽略undefined的影响,只检查属性的实际值类型是否符合条件。 - 数组元素的非空检查:在数组分支中同样使用
NonNullable<E> extends C,确保数组元素的类型判断不受可选属性影响。
内容的提问来源于stack exchange,提问作者Mümin Celal Pinar
相关产品推荐
相关产品推荐

