首页 > 解决方案 > 如何键入在 JS 中创建并在 TSX 文件中使用的自定义 React 挂钩?

问题描述

我有一个自定义钩子,不幸的是,它是用纯 JS 编写的,我在 TypeScript .tsx 文件中使用它。

我这样称呼它

const [toggleDictation, dictationResults] = useDictation()

  useEffect(() => {

    //start recognizing
    toggleDictation();

  }, []);

我在编译器中收到一条错误消息:

This expression is not callable.
  Not all constituents of type 'string | boolean | never[] | (() => Promise<void>)' are callable.
    Type 'string' has no call signatures.ts(2349)

自定义 JS 挂钩中的 toggleDictation 函数写为:


  const toggleDictation = async () => {
    try {
      if (!speechHasStarted) {
        await _startRecognizing();

        return;
      } else {
        await _stopRecognizing();
        return;
      }
    } catch (e) {
      //eslint-disable-next-line
      console.error("Error in toggleDictation, ", e);
      return;
    }
  };

有没有办法进行类型转换或断言以正确设置函数类型以消除错误?

标签: javascriptreactjstypescriptreact-hooks

解决方案


这里真正的问题在于useDictation函数。默认情况下,即使在打字稿中,返回数组的函数也是数组而不是元组类型。

const toggleDictation = async () => { }
const useDictation = () => { // returns Array<(() => Promise<void>) | never[]>
    return [toggleDictation, []]
}

const [tg, arr] = useDictation(); // tg is (() => Promise<void>) | never[] so uncallable

游乐场链接

在 ts 中,您可以添加一个as const或显式类型注释来解决此问题:

const toggleDictation = async () => { }
const useDictation = () => { // returns Array<(() => Promise<void>) | never[]>
    return [toggleDictation, []] as const
}

const [tg, arr] = useDictation(); // tg is now () => Promise<void>
tg() // ok

游乐场链接

对于 JS 我们有一些选择,如果你控制了 js,你可以添加 jsdoc 类型,它们将被 TS 拾取:

const toggleDictation = async () => { }

/**
 * @returns {[()=> Promise<void>, string[])]}
 */
const useDictation = () => {
    return [toggleDictation, []]
}

let [tg, d] = useDictation(); // tg is ()=> Promise<void>
tg() // ok in ts as well 


游乐场链接

或者您可以添加一个声明文件,但这实际上取决于您的设置。如果您为模块创建声明,您将不再从 js 中获得任何推断。您可以d.ts从 js 文件(自 3.7 PR起可用)生成 a 并更正任何声明(例如 的返回类型useDictation

declare const useDictation : () => [()=> Promise<void>, string[]]

let [tg, d] = useDictation(); // tg is ()=> Promise<void>
tg() // ok 

游乐场链接


推荐阅读