简体   繁体   中英

Typescript: This overload signature is not compatible with its implementation signature

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,
  ^^^^^^^^^^^^^
};

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,
  };
}

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> useTabsReturnType<string> | useTabsReturnType<number> instead of useTabsReturnType<string | number> 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM