diff --git a/src/helper.ts b/src/helper.ts index 266ad66..9aa0feb 100644 --- a/src/helper.ts +++ b/src/helper.ts @@ -1,36 +1,72 @@ import { SelectQueryBuilder } from 'typeorm' import { ColumnMetadata } from 'typeorm/metadata/ColumnMetadata' +/** + * Joins 2 keys as `K`, `K.P`, `K.(P` or `K.P)` + * The parenthesis notation is included for embedded columns + */ type Join = K extends string ? P extends string ? `${K}${'' extends P ? '' : '.'}${P | `(${P}` | `${P})`}` : never : never +/** + * Get the previous number between 0 and 10. Examples: + * Prev[3] = 2 + * Prev[0] = never. + * Prev[20] = 0 + */ type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...0[]] -// unwrap Promise type +/** + * Unwrap Promise to T + */ type UnwrapPromise = T extends Promise ? UnwrapPromise : T -// Unwrap Array type +/** + * Unwrap Array to T + */ type UnwrapArray = T extends Array ? UnwrapArray : T -// TODO: puts some comments here, in this ternary of doom +/** + * Find all the dotted path properties for a given column. + * + * T: The column + * D: max depth + */ +// v Have we reached max depth? export type Column = [D] extends [never] - ? never - : T extends Record + ? // yes, stop recursing + never + : // Are we extending something with keys? + T extends Record ? { + // For every keyof T, find all possible properties as a string union [K in keyof T]-?: K extends string - ? T[K] extends Date - ? `${K}` - : T[K] extends Array - ? `${K}` | Join, Prev[D]>> - : T[K] extends Promise - ? U extends Array + ? // Is it string or number (includes enums)? + T[K] extends string | number + ? // yes, add just the key + `${K}` + : // Is it a Date? + T[K] extends Date + ? // yes, add just the key + `${K}` + : // no, is it an array? + T[K] extends Array + ? // yes, unwrap it, and recurse deeper + `${K}` | Join, Prev[D]>> + : // no, is it a promise? + T[K] extends Promise + ? // yes, try to infer its return type and recurse + U extends Array ? `${K}` | Join, Prev[D]>> : `${K}` | Join, Prev[D]>> - : `${K}` | Join> + : // no, we have no more special cases, so treat it as an + // object and recurse deeper on its keys + `${K}` | Join> : never + // Join all the string unions of each keyof T into a single string union }[keyof T] : '' diff --git a/src/paginate.ts b/src/paginate.ts index 5877a6e..7067935 100644 --- a/src/paginate.ts +++ b/src/paginate.ts @@ -70,13 +70,17 @@ export interface PaginateConfig { sortableColumns: Column[] nullSort?: 'first' | 'last' searchableColumns?: Column[] - select?: Column[] | string[] + // see https://github.com/microsoft/TypeScript/issues/29729 for (string & {}) + // eslint-disable-next-line @typescript-eslint/ban-types + select?: (Column | (string & {}))[] maxLimit?: number defaultSortBy?: SortBy defaultLimit?: number where?: FindOptionsWhere | FindOptionsWhere[] filterableColumns?: { - [key in Column | string]?: (FilterOperator | FilterSuffix)[] | true + // see https://github.com/microsoft/TypeScript/issues/29729 for (string & {}) + // eslint-disable-next-line @typescript-eslint/ban-types + [key in Column | (string & {})]?: (FilterOperator | FilterSuffix)[] | true } loadEagerRelations?: boolean withDeleted?: boolean