簡體   English   中英

如何在 TypeScript 中推斷通用回調 function 的返回類型

[英]How to infer the return type of a generic callback function in TypeScript

我在推斷通用回調 function 的類型時遇到問題。 這是我的代碼:

import { FC, createElement, useState, useMemo, createContext as _context, useContext as _useContext } from 'react';

const createContext = <T>(useHook: (providerProps: T) => any) => {
  const ctx = _context({});

  /** Component with provider and initial values calling the hook passed. */
  const Provider: FC<T> = ({ children, ...props }) => {
    const value = useHook(props as T);
    return createElement(ctx.Provider, { value }, children);
  };

  /** Hook will return the context from the provider. */
  const useContext = () => _useContext(ctx) as ReturnType<typeof useHook>;

  /** Function will return the provider and the assign the `displayName` given. */
  const createProvider = (displayName: string) => {
    Provider.displayName = displayName;
    return Provider;
  };

  return {
    useContext,
    createProvider,
  };
};

/** Context with the values to keep track across the app. */
const ctx = createContext<{ _theme: 'light' | 'dark' }>(({ _theme }) => {
  const [theme, setTheme] = useState(_theme);
  return useMemo(() => ({ theme, setTheme }), [theme]);
});

/** Provider for the values of the theme of the app. */
export const AppThemeProvider = ctx.createProvider('AppThemeProvider');

const useAppTheme = () => {
  const { theme } = ctx.useContext();
}

我只想要一種更簡潔的方式來創建上下文,而無需提供提供程序和一些鈎子。 我遇到的問題是在as ReturnType<typeof useHook>行中沒有推斷出返回類型。 它顯示一切。 我想要與 useHook function 返回的類型相同。

在鈎子 useAppTheme 行const { theme } = ctx.useContext(); 主題類型是任何類型,但它應該是'light' | 'dark' 'light' | 'dark'

有人可以幫助我嗎? 請。

謝謝!

在您的版本中,您明確地將useHook參數的返回類型注釋為any ,這就是編譯器所看到的。 如果您希望能夠根據作為useHook傳入的實際回調值的返回類型來縮小范圍,那么您還需要在該類型中使createContext通用,例如:

const createContext = <T, R>(useHook: (providerProps: T) => R) => ...

然后在實現中使用R而不是ReturnType<typeof useHook>


但是您不想手動指定TR 您想手動指定T但讓編譯器推斷R ,不幸的是 TypeScript 目前不支持此功能。 編譯器將嘗試推斷所有類型參數,或者您必須手動指定所有這些參數。 沒有microsoft/TypeScript#26242中要求的“部分類型參數推斷”。 所以你需要解決它。

我能想到兩種解決方法。


第一種是讓編譯器通過手動注釋回調參數而不是直接指定類型參數來推斷TR

const ctx = createContext(({ _theme }: { _theme: 'light' | 'dark' }) => {
  const [theme, setTheme] = useState(_theme);
  return useMemo(() => ({ theme, setTheme }), [theme]);
});

對於createContext的調用者來說,這或多或少的工作量是相同的,但現在編譯器可以對TR使用類型推斷,並且一切正常:

ctx.useContext().theme // "light" | "dark"

我喜歡這種方法,因為它相當自然,但如果你真的希望有人寫createContext<{ _theme: 'light' | 'dark' }>(...) createContext<{ _theme: 'light' | 'dark' }>(...)然后繼續閱讀。


另一種解決方法是使用柯里化,這樣您就可以使用一個類型參數的 function 而不是兩個類型參數的 function,它返回另一個類型參數的 ZC1C425268E68385D1AB5074C17A94

const createContext = <T>() => <R>(useHook: (providerProps: T) => R) => ...

現在你有一個 function 可以手動指定T和另一個 function 編譯器可以推斷R

const ctx = createContext<{ _theme: 'light' | 'dark' }>()(({ _theme }) => {
  const [theme, setTheme] = useState(_theme);
  return useMemo(() => ({ theme, setTheme }), [theme]);
});

ctx.useContext().theme // "light" | "dark"

這樣做的缺點是奇怪的構造foo<T>()(x, y, z)而不是foo<T>(x, y, z) 但它確實運作良好。 由您決定哪種解決方法最適合您的需求。

Playground 代碼鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM