typescript - De ce suprascrierea funcțiilor nu generează o eroare?


function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
    return x + '1';
}

De ce TypeScript este de acord cu această suprasarcină de funcție? Vreau să limitez numărul de intrare la ieșire numerică și șirul de intrare la ieșire de tip șir.

În implementarea funcției mele, am lăsat în mod deliberat ca șirul de intrare numeric să fie afișat. Și mă așteptam ca un mesaj de eroare să fie generat la compilarea acestui fișier ts, dar nu s-a întâmplat. De ce?

MEDIU: Fără tsconfig.json și versiunea tsc este 4.4.3

Răspuns #1

Typescript nu este perfect. Verifică problema #13235 de pe Github pentru mai multe informații despre această imperfecțiune particulară.

Practic, funcția ta de implementare nu știe că există semnături suprascrise. Și este tipizată să returneze string | number și returnează string, ceea ce este un tip perfect valid de returnat. Este atât de simplu.

Și da, în acest caz ai putea avea o eroare de tip la execuție chiar dacă codul se compilează fără eroare. Este un punct nevăzut pe care nu există un mod bun de a-l acoperi.

De ce este totuși imperfect? Ei bine, din acel issue de pe Github este acest citat care oferă puțină mai multă claritate asupra acestuia.

Nu pare să existe prea multe dovezi că oamenii fac greșeli aici în mod regulat într-un mod pe care l-am putea detecta fiabil fără a introduce rezultate fals pozitive. Dar adevărata problemă este că orice implementare aici va fi cel puțin O(n^2) în funcție de numărul de semnături, și există multe fișiere .d.ts care au literalmente zeci de semnături per funcție. Costul și complexitatea verificării „corectitudinii” suprasarcinilor de fiecare dată când erorile sunt atât de rare de la început nu par să merite.

Răspunsul #2

Pentru ce merită, în cazul tău probabil ar fi mai bine să folosești generice.

Vrei ca tipul de ieșire să depindă de tipul de intrare:

function reverse<T extends string | number>(x: T): T {
  // ...
}