javascript - "Det här uttrycket kan inte anropas" i Typescript med typsmala


Jag definierar en funktion med samma signatur som Reacts useState:

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

Här är en del av funktionen:

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

Jag får det här felet:

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

Betyder inte T & Function att T är en funktion, så den skulle kunna anropas? Hur kan jag fixa detta utan tvingade typomvandlingar?

Svar #1

Typen kan framgångsrikt avgränsas med initialState instanceof Function:

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

Redigera: intressant nog kompilerar detta, men det kommer att misslyckas för vissa kantfall. Till exempel, om initialState är Object.create(Function.prototype). Detta är en instans av Function men är inte anropbar.

Svar #2

Det enklaste sättet skulle vara att säga till kompilatorn att initialState är en funktion när typeof initialState är 'function'.

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';
}

Relaterade artiklar