A function that has a parameter with a conditional type should return conditionally based on that. Is that possible?
I have a function that takes one parameter, which is either a custom type (QueryKey) or a function:
export function createHandler(
createQueryKeyOrQueryKey: QueryKey | ((idForQueryKey: string) => QueryKey),
) { ... }
Based on this parameter, I need to return different types from the createHandler function:
return {
createState:
typeof createQueryKeyOrQueryKey !== "function"
? (data) => createState(data, createQueryKeyOrQueryKey)
: (data, id) => createState(data, createQueryKeyOrQueryKey(id)),
};
What is returned with createState is also conditional:
createState:
| ((data: TData) => State)
| ((data: TData, idForQueryKey: string) => State);
When creating a handler via createHandler, there should be two ways to use it:
handler.createState({ a: 123 })
handler.createState({ a: 123 }, "some-id")
...but only one variant of createState should be allowed at a time. Which one is allowed should be based on how the handler is created, where either a query key OR a function is used:
// Option 1:
//
// query key directly
const queryKey = "some-query-key"
const handler1 = createHandler(queryKey)
// ✅ should be allowed
handler1.createState({ a: 123 })
// ❌ should not be allowed
handler1.createState({ a: 123 }, "some-id")
// Option 2:
//
// query key as function for creation
const queryKeyCreator = (id: string) => "some-query-key" + id
const handler2 = createHandler(queryKeyCreator)
// ❌ should not be allowed
handler2.createState({ a: 123 })
// ✅ should be allowed
handler2.createState({ a: 123 }, "some-id")
Right now, the return type does not work correctly (data is any):
Why so? TypeScript knows that createState is conditional and the one where the return function only has one parameter (data) is also a valid type based on the type of createState.
BTW: Is there maybe a better way to solve this problem? Function overloading or discriminating unions via key would maybe work, but I'm not 100% sure how the different implementations can be based on the caller's decision which variant (key or function) is used.
