如何在柯里化函数中推断泛型?

Posted

技术标签:

【中文标题】如何在柯里化函数中推断泛型?【英文标题】:How to infer generic in a curried function? 【发布时间】:2020-08-20 19:22:37 【问题描述】:

我正在尝试输入一个用于查询集合的 API。我希望它像这样使用:

interface Car 
  model: string
  doors: 2 | 4 | 5
  designers: string[]


const result = query(
  model: [ contains('tesla') ],
  doors: [ is(3) ],
  designers: [ includes('Franz') ],
  take: 5,
);

所以这是我不完美的方法:

type Query<Entity extends EntityType> = (config: QueryConfig<Entity>) => Promise<Entity[]>
type QueryConfig<Entity extends EntityType> =
   [K in FilterScalarMembers<Entity>]?: ScalarBuilderFn<Entity[K]>[] 
  &  [K in FilterCollectionMembers<Entity>]?: CollectionBuilderFn<Entity[K]>[] 
  &  take: number ;

type FilterCollectionMembers<Entity extends EntityType> =
   [K in keyof Entity]: Entity[K] extends CollectionType ? K : never [keyof Entity]

type FilterScalarMembers<Entity extends EntityType> =
   [k in keyof Entity]: Entity[k] extends (string | number) ? k : never [keyof Entity]

type ScalarBuilderFn<T extends string | number> = (builder: ScalarQueryBuilder<T>) => ScalarQueryBuilder<T>
type CollectionBuilderFn<T extends CollectionType> = (builder: CollectionQueryBuilder<T>) => CollectionQueryBuilder<T>
type ScalarQueryBuilder<T extends string | number> = 
type CollectionQueryBuilder<T extends CollectionType> = 
type EntityType = Record<string, any>
type CollectionType = ((string | number)[]) | Set<string | number>

const is = <T extends string | number>(arg: T): ScalarBuilderFn<T> => function()  as unknown as ScalarBuilderFn<T>;

问题在这里变得很明显:doors: [ is(3) ] 因为类型没有缩小到2 | 4 | 5,TypeScript 不会给出关于3 参数的错误。我们可以对is 函数做些什么来帮助它正确推断类型吗?

【问题讨论】:

【参考方案1】:

您可以使用indexed types:

const result = query(
    doors: [is<Car['doors']>(3)]
);

您可以将is 传递给Car['doors'] 的通用参数,这将告诉is 它的参数必须可分配给Car['doors'],即2 | 4 | 5

我不确定您是否需要所有这些类型 - 除非它们执行此处未显示的其他操作。你所需要的只是is 有一个泛型类型参数,它的参数需要匹配

const is = <T>(val: T) =>   // rest of the implementation

【讨论】:

正如我所提到的,我希望从使用 is 的上下文中推断出 is 参数类型。手动指定泛型类型很容易出错。

以上是关于如何在柯里化函数中推断泛型?的主要内容,如果未能解决你的问题,请参考以下文章

浅谈函数柯里化

js之柯里化与反柯里化

柯里化与反柯里化

如何在 Rust 中实现多级柯里化函数?

面试官:什么是函数柯里化?能手写实现吗?

js函数式编程-柯里化