I’m writing a fetch()
wrapper that takes an options argument. Normally this wrapper will camel case the return value, but if the dontCamelize
option is set to true, then it should wrap the return value in a Decamelize<>
generic. I’m not sure how to express this in TypeScript though.
Because there could be several options properties, I don’t think I can use function overrides. I tried to express it with a ResponseType helper and a conditional type but it doesn’t seem to work. Any help is much appreciated!
TS Playground
type Decamelize<T> = {
[K in keyof T as K extends string ? `${Uncapitalize<K>}` : K]: T[K]
};
type Options = {
dontCamelize?: boolean;
verbose?: boolean;
// Add more options here as needed
option1?: string;
option2?: number;
option3?: boolean;
};
type ResponseType<T, O extends Options> =
O['dontCamelize'] extends true ? Decamelize<T> : T;
export function fetcher<T, O extends Options = {}>(
subject: T,
options: O = {} as O
): ResponseType<T, O> {
return subject as any;
}
// Usage examples
const res1 = fetcher<{ fooBar: 'baz' }>({ fooBar: 'baz' }); // Expect: { fooBar: 'baz' }
const res2 = fetcher<{ fooBar: 'baz' }>({ fooBar: 'baz' }, { dontCamelize: true }); // Expect: Decamelize<{ fooBar: 'baz' }>
const res3 = fetcher<{ fooBar: 'baz' }>({ fooBar: 'baz' }, { verbose: true }); // Expect: { fooBar: 'baz' }
const res4 = fetcher<{ fooBar: 'baz' }>({ fooBar: 'baz' }, { dontCamelize: true, verbose: true }); // Expect: Decamelize<{ fooBar: 'baz' }>
2