Website-Suche

javascript - „Dieser Ausdruck ist nicht aufrufbar“ in Typescript mit Typverengung


Ich definiere eine Funktion mit der gleichen Signatur wie Reacts useState:

declare function useState<S>(
  initialState: S | (() => S),
): [S, React.Dispatch<React.SetStateAction<S>>];

Hier ist ein Teil der Funktion:

function foo<T>(initialState: T | (() => T)) {
  typeof initialState === 'function' ? initialState() : initialState;
}

Ich bekomme diesen Fehler:

This expression is not callable.
  Not all constituents of type '(() => T) | (T & Function)' are callable.
    Type 'T & Function' has no call signatures.(2349)

Bedeutet T & Function nicht, dass T eine Funktion ist, also aufrufbar? Wie kann ich das ohne erzwungene Typumwandlungen beheben?

Antwort #1

Der Typ kann erfolgreich mithilfe von initialState instanceof Function eingegrenzt werden:

function foo<T>(initialState: T | (() => T)) {
  initialState instanceof Function ? initialState() : initialState;
}

Bearbeiten: Interessanterweise kompiliert das, aber es wird bei einigen Randfällen fehlschlagen. Zum Beispiel, wenn initialState Object.create(Function.prototype) ist. Dies ist eine Instanz von Function, ist aber nicht aufrufbar.

Antwort #2

Der einfachste Weg wäre, dem Compiler zu sagen, dass initialState eine Funktion ist, wenn typeof initialState 'function' ist.

function foo<T>(initialState: T | (() => T)) {
  if (isFunction(initialState)) {
    initialState();
  } else {
    initialState;
  }
}

function isFunction<T>(f: T | (() => T)): f is (() => T) {
  return typeof f === 'function';
}

Verwandte Artikel