How to make the params conditional only if no generic supplied?
type Params<T> = T extends Record<string, string> ? T : never;
export const getPath =
<T>(path: string) =>
(params: Params<T>) => {
const lang = getCurrentLang();
return generatePath(path, { lang, ...(params ?? {}) });
};
For example:
const login = getPath("/:lang/login")
login() // should works without types error
const book = getPath<{ id: string }>("/:lang/books/:id")
book() // error
book({ id: "1" }) // works
You can use generics in combination with a conditional type to enforce a certain return type for getPath(). Let your generic parameter T extend a Union Type of your conditional return value and something that is not assinable to that value (e. g. undefined) so you can check if a generic argument was passed or not.
If a generic argument was passed, return (param: T) => ... otherwise just () => ....
This logic can be simplified even more using tuples in rest parameters and spread expressions:
(...params: T extends Record<string, string> ? [T] : [] ) => any
export const getPath = <
T extends Record<string, string> | undefined = undefined
>(
path: string
): ((
...params: T extends Record<string, string> ? [T] : []
) => any) => {
return null as any; // ignoring the implemetation
};
const login = getPath("/:lang/login");
login(); // works
const book = getPath<{id: string}>("/:lang/books/:id");
// ^? const book: (param: {id: string;}) => any
book(); // error
book({id: "1"}); // works
TypeScript Playground
P. S. Note, I removed the function implementation as I don't know how getCurrentLang() and generatePath() are defined or what their return type is.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With