My API is quite generic and I'm looking for a typed TypeScript client solution. Currently, my code looks like this:
export type EntityTypes =
| 'account'
| 'organization'
| 'group'
export function getListByValue<TEntityColumns>(
entity: EntityTypes,
filterColumn: keyof TEntityColumns,
filterValue: any) {
apiRequest({
entityType: entity,
filter: {
column: filterColumn,
value: filterValue,
op: '='
}
});
}
While this approach works, there are some drawbacks:
- I need to manually set the generic parameter each time.
- The generic parameter is not required (although there's a workaround).
- There can be accidental mismatches between the generic parameter and entity type literal parameter.
Is there a way to bind the TEntityColumns
type with EntityTypes
into a single structure in order to make the API type safe, so that minimal typing would result in maximum autocompletion and type safety?
Update I was seeking a generic solution on how to combine literal types with type selection and thus did not include my current definition of TEntityColumns which is:
- Quite complex and
- I cannot modify it as it is part of the internal SDK
With my current definition, I am able to write code like this:
getListByValue<AccountColumns>('account', 'name', 'John');
// I could omit the generic parameter but then I lose type safety
getListByValue('account', 'name', 'John');
// Also, I can do this and the compiler will not catch the error
getListByValue<OrganizationColumns>('account', 'VAT number', '123456')
Therefore, I would like to have something similar to this (or maybe there is another option that I am unaware of):
// omit the generic
getListByValue('account', 'name', 'John');
// or just use the generic
getListByValue<AccountColumns>('name', 'John')
export declare type EntityColumns<T extends {
[name: string]: ColumnDef;
}> = {
[P in keyof T]: EntityColumnValue<T[P]>;
};
export declare type EntityColumnValue<T extends ColumnDef> =
T['type'] extends 'boolean' ? boolean | undefined :
T['type'] extends 'number' ? number | undefined :
T['type'] extends 'number-array' ? number[] | undefined : ...
export declare type ColumnDef = {
type: 'boolean';
index?: boolean;
} | {
type: 'number';
index?: boolean | 'unique';
} | {
type: 'number-array';
index: boolean;
} | ...