【问题标题】:React Typescript Generic Type Overloading (e.g. useState)React Typescript 泛型类型重载(例如 useState)
【发布时间】:2021-05-21 16:04:48
【问题描述】:

我正在尝试创建一个重载函数,该函数将写入和写入会话存储而不是标准状态。我希望它在我只提供类型而不是初始值的情况下是可重载的。就像 useState 在 react 中所做的一样。

这是我目前所拥有的:

export function useSessionState<S = undefined>(initialState?: S): [S, (state: S) => void];
export function useSessionState<S>(initialState: S): [S, (state: S) => void] {
  const [state, setState] = useState<S>()

  // Unimportant: Do something to load to and from session storage.

  return [state, (value) => {

  }]
}

当我尝试使用这种类型时,我只会得到其中一个重载的结果类型。

// Variable 'state' is a string as expected.
const [state, setState] = useSessionState("some_initial_value")

// Variable 'undefinedState' is also a string, but it should be undefined since no 'initialState' was provided.
const [undefinedState, setUndefinedState] = useSessionState<string>()

【问题讨论】:

    标签: javascript reactjs typescript overloading


    【解决方案1】:

    我自己也不知道答案,所以我开始阅读和尝试。我的尝试非常接近,但我发现了以下缺陷:

    • 两次尝试都将initialState 显示为S 类型,而不是S | undefined,这意味着您很难在没有强制转换的情况下实现此功能。
    • 第一种方案和第二种方案生成的.d.ts不同。我相信第一次尝试的.d.ts 更接近官方的useState 定义。
    • 即使您没有提及:
      • initialState 可以是一个值,也可以是一个函数,这只是第二次尝试的情况。
      • setState 函数应该有一个S | undefined 类型的参数,而不是S

    希望有更好的解决方案... 如果只有 actual implementation 是用 Typescript 编写的。

    尝试 1:Conditional types

    Playground

    function useState<S>(initialState: S): [S, (state: S) => void];
    function useState<S = undefined>(): [S | undefined, (state: S) => void];
    function useState<S = undefined>(initialState?: S): [S extends undefined ? undefined | S : S, (state: S) => void] {
      throw new Error(`Not implemented and not using ${initialState}`);
    }
    
    const [state1, setState1] = useState<string>("initialValue"); // string
    const [state2, setState2] = useState("initialValue"); // string
    const [state3, setState3] = useState<string>(); // undefined | string
    const [state4, setState4] = useState(); // undefined
    

    在操场上生成的.d.ts

    declare function useState<S>(initialState: S): [S, (state: S) => void];
    declare function useState<S = undefined>(): [S | undefined, (state: S) => void];
    

    尝试 2:没有条件类型

    Playground

    type Dispatch<T> = (value: T) => void;
    
    function useState<S = undefined>(): [S | undefined, Dispatch<S | undefined>];
    function useState<S>(initialState?: S | (() => S)): [S, Dispatch<S>];
    function useState<S>(initialState?: S | (() => S)): [S, Dispatch<S>] {
        throw new Error(`Not implemented and not using ${initialState}`);
    }
     
    const [state1, setState1] = useState<string>("initialValue"); // string
    const [state2, setState2] = useState("initialValue"); // string
    const [state3, setState3] = useState<string>(); // undefined | string
    const [state4, setState4] = useState(); // undefined
    

    在操场上生成的.d.ts

    declare function useState<S = undefined>(): [S | undefined, Dispatch<S | undefined>];
    declare function useState<S>(initialState?: S | (() => S)): [S, Dispatch<S>];
    

    【讨论】:

    • 编辑添加第二次尝试。
    猜你喜欢
    • 2021-11-19
    • 2021-04-23
    • 2022-12-03
    • 2017-05-13
    • 2019-05-30
    • 2020-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多