unknown în TypeScript

Tipuri de bază TypeScript 3.0

Tipul sigur pentru valori necunoscute: acceptă orice, dar nu poți folosi valoarea până nu verifici ce tip are.

Sintaxă
let x: unknown = valoare;
if (typeof x === "string") { /* aici x este string */ }

Ce face unknown

unknown este perechea sigură a lui any. Orice valoare poate fi pusă într-o variabilă unknown, dar nu poți face nimic cu ea (să citești o proprietate, să apelezi o metodă, să aduni) până nu dovedești ce tip are. Dovada se face cu o verificare: typeof, instanceof, in sau o funcție predicat.

După verificare, în interiorul lui if, TypeScript știe tipul exact (vezi narrowing). Este tipul potrivit pentru date venite din afară: JSON.parse, răspunsuri de la server, mesaje primite.

În modul strict, variabila din catch (e) are tipul unknown, pentru că în JavaScript se poate arunca orice, nu doar obiecte Error.

Exemple

Exemplul 1: Verificare înainte de folosire

Funcția primește orice valoare și decide ce face după tipul ei real.

function descrie(x: unknown): string {
    if (typeof x === "string") return `text cu ${x.length} litere`;
    if (typeof x === "number") return `număr: ${x.toFixed(1)}`;
    if (Array.isArray(x)) return `tablou cu ${x.length} elemente`;
    return "altceva";
}

console.log(descrie("Iași"));
console.log(descrie(9.25));
console.log(descrie([1, 2, 3]));
console.log(descrie(null));

Rezultat

text cu 4 litere
număr: 9.3
tablou cu 3 elemente
altceva

Exemplul 2: Fără verificare, valoarea nu se poate folosi

Cu any codul ar compila; cu unknown tsc cere o verificare.

const date: unknown = JSON.parse('{"nume": "Ana"}');
console.log(date.nume);

Eroarea afișată de tsc

exemplu.mts(2,13): error TS18046: 'date' is of type 'unknown'.

Exemplul 3: Eroarea din catch este unknown

Înainte de e.message verifici că e este un Error.

function citesteNota(text: string): number {
    const n = Number(text);
    if (Number.isNaN(n)) throw new Error(`„${text}” nu este o notă`);
    return n;
}

for (const text of ["9", "zece"]) {
    try {
        console.log("Nota:", citesteNota(text));
    } catch (e) {
        if (e instanceof Error) console.log("Eroare:", e.message);
        else console.log("Eroare necunoscută:", e);
    }
}

Rezultat

Nota: 9
Eroare: „zece” nu este o notă

Greșeli frecvente

  • Faci date as Elev imediat după JSON.parse. Compilează, dar nu verifică nimic: dacă datele arată altfel, eroarea apare mai târziu. Verifică proprietățile sau folosește un predicat de tip.
  • Folosești any pentru date externe din obișnuință. unknown costă câteva rânduri de verificare și te scapă de erori la rulare.

Comenzi înrudite

  • any: Tipul care oprește verificarea: o valoare any acceptă orice și poate fi folosită oricum, fără erori de compilare.
  • narrowing: TypeScript urmărește verificările din cod (if, switch, return) și restrânge tipul unei variabile în fiecare ramură.
  • typeof guard: Verificarea typeof x === „string” (sau „number”, „boolean”…) restrânge tipul la primitivul respectiv.
  • predicat de tip (is): O funcție cu rezultatul x is Tip spune compilatorului că, dacă returnează true, x are tipul Tip.
  • never: Tipul fără nicio valoare: pentru funcții care nu se termină normal și pentru cazurile imposibile din cod.