Reputation: 442
I have a custom hook that is unfortunately written in pure JS that I am using in a TypeScript .tsx file.
I'm calling it like
const [toggleDictation, dictationResults] = useDictation()
useEffect(() => {
//start recognizing
toggleDictation();
}, []);
I get an error in the compiler that says:
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)
the toggleDictation function in the custom JS hook is written as:
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;
}
};
Is there a way to typecast or assert this to set the function type correctly to remove the error?
Upvotes: 1
Views: 3474
Reputation: 250336
The real problem here is with the useDictation
function. By default, even in typescript a function returning an array is an array not a tuple type.
const toggleDictation = async () => { }
const useDictation = () => { // returns Array<(() => Promise<void>) | never[]>
return [toggleDictation, []]
}
const [tg, arr] = useDictation(); // tg is (() => Promise<void>) | never[] so uncallable
In ts you can add an as const
or an explicit type annotation to fix this:
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
For JS we have some options, if you control the js, you can add jsdoc types and they will be picked up by 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
Or you can add a declaration file, but that really depends on your setup. If you create a declaration for a module, you will not get any more inference from js. You could generate a d.ts
from the js files (available since 3.7 PR) and correct any declarations (such as the return type of useDictation
)
declare const useDictation : () => [()=> Promise<void>, string[]]
let [tg, d] = useDictation(); // tg is ()=> Promise<void>
tg() // ok
Upvotes: 4
Reputation: 49
Typing this shouldn't have an impact on the compiled result. Of course, if this works in a plain JS file, what i'm saying is false, but the problem seems to lie in the implementation rather than the lack of typing.
Upvotes: 1