Menu

Funkcje w TypeScript: typy parametrów, typ zwracany, void

Jak typować funkcje w TypeScript: adnotacja każdego parametru, adnotacja albo wnioskowanie typu zwracanego, void dla funkcji, które nic nie zwracają, oraz typowanie funkcji strzałkowych, wyrażeń funkcyjnych, funkcji async i parametru this.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Funkcja w TypeScript to funkcja JavaScript z typami parametrów i opcjonalnie z typem wartości zwracanej. Każdy parametr dostaje adnotację, typ zwracany stoi po liście parametrów, a kompilator sprawdza względem nich każde wywołanie.

Oba błędne wywołania to błędy kompilacji (TS2345 i TS2554). Komentarze // @ts-expect-error mówią kompilatorowi, że w następnej linii spodziewany jest błąd, więc reszta pliku nadal się uruchamia. Usuń jeden z nich i uruchom ponownie, aby zobaczyć prawdziwy komunikat.

Typy parametrów

Każdy parametr zapisuje się jako name: Type. Przy strict, który w TypeScript 7 jest domyślnie włączony, parametr bez adnotacji i bez kontekstu do wnioskowania to błąd: Parameter 'x' implicitly has an 'any' type. (TS7006). W praktyce więc każdy parametr samodzielnej funkcji ma adnotację.

Jako typ parametru działa każdy typ: prymitywy, tablice, typy obiektowe, unie, inne funkcje.

TypeScript sprawdza też liczbę argumentów. Przekazanie większej lub mniejszej liczby, niż deklaruje funkcja, to błąd, w odróżnieniu od zwykłego JavaScriptu, który brakujące uzupełnia wartością undefined, a nadmiarowe ignoruje. Jak uczynić parametr opcjonalnym lub nadać mu wartość domyślną, opisuje strona o parametrach opcjonalnych.

Typy zwracane: adnotacja czy wnioskowanie

Typ zwracany stoi po nawiasie zamykającym: function f(): Type. Jest opcjonalny. Bez niego TypeScript wnioskuje typ z każdego return w ciele funkcji.

Adnotacja się opłaca, gdy funkcja jest eksportowana, ma kilka ścieżek zwracania albo jest rekurencyjna. Błąd pojawia się wtedy wewnątrz funkcji, przy złym return, a nie u wywołującego. Klasyczny przypadek to gałąź, w której brakuje return:

Kompilator zgłasza index.ts(2,32): error TS2366: Function lacks ending return statement and return type does not include 'undefined'. Dodaj na końcu return "C";, a kod się uruchomi. Bez adnotacji : string funkcja skompilowałaby się z wywnioskowanym typem "A" | "B" | undefined, a problem przeniósłby się do tego, kto używa wyniku.

void: funkcje, które nic nie zwracają

Funkcja, która tylko coś robi (loguje, zapisuje, modyfikuje), ma typ zwracany void. TypeScript wnioskuje go, gdy nie ma return z wartością, i można go też zapisać jawnie.

Te reguły dotyczące void często zaskakują:

SytuacjaDozwolone?
function f(): void { return 42; }Nie: Type 'number' is not assignable to type 'void'. (TS2322)
const f: () => void = () => 42;Tak: wartość jest zwracana, ale wywołujący nie mogą na niej polegać
function f(): undefined {}Tak (TypeScript 5.1 i nowsze)
Użycie wyniku funkcji void w ifNie: An expression of type 'void' cannot be tested for truthiness. (TS1345)

Drugi wiersz jest celowy. Dzięki niemu arr.forEach(x => list.push(x)) się kompiluje, choć push zwraca liczbę. void w typie funkcji znaczy „cokolwiek to zwraca, nikt tego nie czyta”. Dla funkcji, która w ogóle nie wraca (zawsze rzuca wyjątek albo działa w nieskończonej pętli), typem zwracanym jest never.

Funkcje strzałkowe i wyrażenia funkcyjne

Funkcje strzałkowe i wyrażenia funkcyjne przyjmują te same adnotacje. Typ zwracany stoi po liście parametrów, przed =>.

Bez nawiasów (x, y) => { x, y } jest blokiem bez return, a funkcja zwraca undefined. Reguły działania funkcji strzałkowych w czasie wykonania (brak własnego this, brak arguments) są takie same jak w JavaScripcie; zobacz funkcje strzałkowe w JavaScript.

Gdy funkcja jest zapisana bezpośrednio jako argument, zwykle w ogóle nie dodaje się adnotacji jej parametrów. TypeScript wie, co otrzymuje callback, z funkcji, do której jest przekazywany (typowanie kontekstowe): w [1, 2].map(n => n * 2) n ma już typ number. Zapisywanie typu funkcji jako wartości, (n: number) => string, opisuje strona o typach funkcji.

Zwracanie kilku wartości

Funkcja zwraca jedną wartość, więc zwróć obiekt albo krotkę i ją zdestrukturyzuj.

Typ zwracany krotki wymaga adnotacji. Bez niej [a, b] jest wnioskowane jako string[]: destrukturyzacja nadal działa, ale typ nie mówi już, że elementy są dokładnie dwa.

Funkcje async

Funkcja async zawsze zwraca Promise. Zapisz typ zwracany jako Promise<T>, gdzie T to to, co funkcja zwraca w środku.

async function loadScore(id: number): Promise<number> {
  await new Promise((resolve) => setTimeout(resolve, 10));
  return id * 10;
}

async function main(): Promise<void> {
  const score = await loadScore(4); // score: number
  console.log("score", score);
}

main();

Zapis async function f(): number to błąd: The return type of an async function or method must be the global Promise<T> type. Did you mean to write 'Promise<number>'? (TS1064).

Parametr this

JavaScript ustala this w chwili wywołania. TypeScript pozwala zadeklarować, czym musi być this, za pomocą sztucznego pierwszego parametru o nazwie this. Jest on usuwany ze skompilowanego JavaScriptu, a wywołujący go nie przekazują.

interface Counter {
  count: number;
}

function increment(this: Counter, by: number): void {
  this.count += by;
}

const c = { count: 0, increment };
c.increment(2); // fine: this is c

increment(2);
// error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'Counter'.

Bez parametru this wewnątrz samodzielnej funkcji this jest niejawnym any, a tryb strict zgłasza 'this' implicitly has type 'any' because it does not have a type annotation. (TS2683). W metodach klas this ma już typ instancji klasy, więc ten parametr przydaje się głównie w samodzielnych funkcjach dołączanych do obiektów i w callbackach, które biblioteki wywołują z określonym this.

Najczęściej zadawane pytania

Jak określić typ zwracany funkcji w TypeScript?

Po liście parametrów napisz dwukropek i typ: function total(a: number, b: number): number { ... }. W funkcji strzałkowej trafia w to samo miejsce: const total = (a: number, b: number): number => a + b;. Jeśli go pominiesz, TypeScript wywnioskuje typ zwracany z instrukcji return.

Czy zawsze trzeba dodawać adnotację typu zwracanego w TypeScript?

Nie, bo typ zwracany jest wnioskowany. Dodawaj go w funkcjach eksportowanych i w funkcjach z kilkoma ścieżkami return: adnotacja dokumentuje kontrakt, a błędny return jest wtedy zgłaszany wewnątrz funkcji, a nie u jakiegoś odległego wywołującego.

Czym różni się void od undefined w TypeScript?

void znaczy „wywołujący nie powinien używać wartości zwracanej”. undefined to konkretny typ wartości. Funkcja zadeklarowana jako (): void nie może zwrócić wartości, ale typ callbacku () => void przyjmuje funkcję, która coś zwraca, a wynik jest po prostu ignorowany. Używaj void dla funkcji, które nic nie zwracają, a undefined tylko wtedy, gdy wywołujący naprawdę porównuje wynik z undefined.

Jak zwrócić kilka wartości z funkcji w TypeScript?

Zwróć obiekt ({ min: number; max: number }) albo krotkę ([number, number]) i zdestrukturyzuj ją w miejscu wywołania. Obiekty są czytelniejsze, gdy wartości mają różne znaczenia; krotki dobrze sprawdzają się przy krótkich parach, takich jak [value, setValue].

Jaki typ zwraca funkcja async w TypeScript?

Zawsze Promise. Funkcja async, która zwraca number, ma typ zwracany Promise<number>, a zapis : number jest w niej błędem kompilacji (TS1064). Funkcja, która nic nie zwraca, ma typ Promise<void>.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ