Reputation: 747
The following code works if I exclude the setCurrentTab
from the return interface useTabsReturnType
but not if I include it and I don't know why
interface useTabsReturnType<T> {
currentTab: T;
setCurrentTab: React.Dispatch<React.SetStateAction<T>>;
}
export function useTabs(defaultValues: number): useTabsReturnType<number>;
//This overload signature is not compatible with its implementation signature.ts(2394)
export function useTabs(defaultValues: string): useTabsReturnType<string>;
export function useTabs(defaultValues?: string | number): useTabsReturnType<string | number> {
const [currentTab, setCurrentTab] = useState(defaultValues || '');
return {
currentTab,
setCurrentTab,
};
}
edit: after following Radu Diță's suggestion I got this error:
Type 'Dispatch<SetStateAction<string | number>>' is not assignable to type 'Dispatch<SetStateAction<string>> | Dispatch<SetStateAction<number>>'.
Type 'Dispatch<SetStateAction<string | number>>' is not assignable to type 'Dispatch<SetStateAction<string>>'.
Type 'SetStateAction<string>' is not assignable to type 'SetStateAction<string | number>'.
Type '(prevState: string) => string' is not assignable to type 'SetStateAction<string | number>'.
Type '(prevState: string) => string' is not assignable to type '(prevState: string | number) => string | number'.
Types of parameters 'prevState' and 'prevState' are incompatible.
Type 'string | number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.ts(2322)
useTabs.ts(20, 3): The expected type comes from property 'setCurrentTab' which is declared here on type 'useTabsReturnType<number> | useTabsReturnType<string>'
The error came from here:
return {
currentTab,
setCurrentTab,
^^^^^^^^^^^^^
};
Upvotes: 0
Views: 321
Reputation: 7341
Why don't you simply let your useTabs
function be generic?
export function useTabs<T extends string | number>(defaultValues: T): useTabsReturnType<T> {
const [currentTab, setCurrentTab] = useState(defaultValues);
return {
currentTab,
setCurrentTab,
};
}
Upvotes: 1
Reputation: 14171
A quick fix is to change the return
type for the implementation of the function. Something like this:
export function useTabs(defaultValues?: string | number): useTabsReturnType<string> | useTabsReturnType<number> {
const [currentTab, setCurrentTab] = useState(defaultValues || '');
return {
currentTab,
setCurrentTab,
};
}
The important part is this: useTabsReturnType<string> | useTabsReturnType<number>
instead of useTabsReturnType<string | number>
Another solution is to use type
and allow TS
to distribute the union. Something like this:
type useTabsReturnType<T> = T extends any ? {
currentTab: T;
setCurrentTab: React.Dispatch<React.SetStateAction<T>>;
} : never
With this change you don't need to change the return type of your function.
Upvotes: 0