如何在TypeScript中提取此复杂类型定义中的泛型类型



https://stackblitz.com/edit/xh93ag?file=index.ts

考虑一下我有这些类型的

type TDomainConditionOperator =
'=' | '!=' | '>' | '>=' | '<' | '<=' | '=?' |
'=like' | 'like' | 'not like' | 'ilike' | 'not ilike' | '=ilike' |
'in' | 'not in' | 'child_of' | 'parent_of'
;
type TDomainCondition = [string, TDomainConditionOperator, any];
export type TDomain = TDomainCondition | '|' | '&' | '!';
export type TReferenceValue<T, TypeOnly extends boolean = false> = TypeOnly extends true ?
T :
T | number | Upsert<T>;
export type TToOne<T, TypeOnly extends boolean = false> = TypeOnly extends true ?
TReferenceValue<T, TypeOnly> :
TReferenceValue<T, TypeOnly> | Domains;
export type TToMany<T, TypeOnly extends boolean = false> = TypeOnly extends true ?
Array<TReferenceValue<T, TypeOnly>> :
Array<TReferenceValue<T, TypeOnly>> | Domains | ToManyCommands;
class Domains {}
class ToManyCommands {}
class Upsert<T> {}

我创建了这种类型,用于从TToManyTToOne中提取T

export type ExtractOdooRelation<T> = (
T extends TToMany<infer S> ?
(
Exclude<S, Domains | ToManyCommands> extends Array<infer S1> ?
S1 : 1
) : (
T extends TToOne<infer R> ?
Exclude<R, Domains> : 2
)
) extends TReferenceValue<infer R1, boolean> ?
Exclude<R1, number | Upsert<T>> : 3
;

然而,它并没有像预期的那样发挥作用。

class StockMove {}
// I expect it resolves as type  StockMove but not never
const whyIsThisType_Never: ExtractOdooRelation<TToMany<StockMove, false>>;

什么似乎缺失或错误?


我的目标是编写一种类型,用于自动完成下面的对象结构

class ResPartner {
name: string;
}
class ResGroup {
name: string;
}
class ProductProduct {
name: string;
}
class StockMove {
group_id: TToOne<ResGroup>;
product_id: TToOne<ProductProduct>;
partner_id: TToOne<ResPartner>;
}
class StockPicking {
move_lines: TToMany<StockMove>;
}

// Developer should have Typescript type checking and autocomplete backed for writing this object
await stockPickingFactory.deep_search_read<StockPicking>({
move_lines: {
read: ['group_id', 'product_id'],
preload: {
company_id: {
read: ['partner_id'],
preload: {
partner_id: {}
}
},
}
}
});

正确的类型是

export type ExtractOdooRelation<T> =
(
T extends TToMany<infer S> ? (
Exclude<T, Domains | ToManyCommands>
) : (
T extends TToOne<infer S> ?
Exclude<S, Domains> : never
)
// It is a bit weird that need to first infer R before infer Q in Array for TToMany
) extends TReferenceValue<infer R> ? (
R extends Array<infer Q> ?
Exclude<Q, number | Upsert<Q>> :
Exclude<R, number | Upsert<R>>
) : never
;

最新更新