Как вывести generi c в каррированной функции? - PullRequest
2 голосов
/ 06 мая 2020

Я пытаюсь напечатать 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) ] поскольку тип не сузился to 2 | 4 | 5, TypeScript не выдает ошибку относительно аргумента 3. Можем ли мы сделать что-нибудь с функцией is, чтобы помочь ей правильно определить тип?

1 Ответ

0 голосов
/ 06 мая 2020

Вы можете сделать это, используя индексированные типы :

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

Вы можете передать is общий c параметр Car['doors'], который сообщит is, что его Параметр должен быть назначен на Car['doors'], а именно 2 | 4 | 5.

Я не уверен, что вам тогда нужны все эти типы - если они не делают другие вещи, не показанные здесь. Все, что вам нужно, это чтобы is имел один общий параметр типа c, которому должен соответствовать его параметр

const is = <T>(val: T) => { } // rest of the implementation
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...