Menu

Strict mode in TypeScript: cosa attiva strict: true

strict: true in tsconfig.json attiva una famiglia di controlli sui tipi: noImplicitAny, strictNullChecks, strictPropertyInitialization e altri cinque. Scopri cosa intercetta ciascuno, come attivare lo strict mode in un progetto esistente e le opzioni utili che strict non include.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Lo strict mode è l'opzione "strict": true di tsconfig.json. È un unico interruttore per otto opzioni di controllo dei tipi che intercettano any impliciti, null e undefined non controllati, assegnazioni di funzioni non sicure e campi di classe non inizializzati. In TypeScript 7, strict è attivo di default. Ecco come appare del codice che lo supera:

L'output è no user, SyntaxError e 42. Togli il : number, il ?. o il controllo instanceof e il file non compila più.

Come attivarlo

{
    "compilerOptions": {
        "strict": true
    }
}

Le singole opzioni prevalgono su strict, in entrambe le direzioni. "strict": true, "strictNullChecks": false mantiene tutto tranne il controllo su null; "strict": false, "noImplicitAny": true attiva solo quella. strict ti iscrive anche ai controlli aggiunti nelle versioni future, perché le nuove opzioni della famiglia strict entrano nel gruppo.

Lo strict di TypeScript non ha niente a che vedere con la direttiva "use strict" di JavaScript, che è una modalità di esecuzione. TypeScript 7 emette sempre "use strict" dove serve, e impostare alwaysStrict: false è l'errore TS5108 (l'opzione è stata rimossa).

Cosa intercetta ogni opzione

OpzioneCosa segnalaErrore
noImplicitAnyun parametro o una variabile il cui tipo sarebbe silenziosamente anyTS7006 Parameter 'x' implicitly has an 'any' type.
strictNullChecksl'uso di un valore che può essere null o undefinedTS18048 'u' is possibly 'undefined'.
strictFunctionTypesl'assegnazione di una funzione con un tipo di parametro più ristretto del richiestoTS2322
strictBindCallApplyargomenti sbagliati a .call, .bind e .applyTS2345
strictPropertyInitializationun campo di classe che non viene mai assegnatoTS2564 Property 'name' has no initializer and is not definitely assigned in the constructor.
noImplicitThisthis con un tipo any implicito, come in una function annidataTS2683
useUnknownInCatchVariablesl'uso di una variabile di catch prima di restringerla (è unknown)TS18046 'err' is of type 'unknown'.
strictBuiltinIteratorReturntrattare it.next().value di un iteratore built-in come sempre definitoTS2322

Le due che cambiano più codice sono noImplicitAny e strictNullChecks. Questo blocco le viola entrambe di proposito:

Stampa index.ts(2,17): error TS7006: Parameter 'x' implicitly has an 'any' type. e index.ts(11,13): error TS18048: 'user' is possibly 'undefined'. Senza strict, compila e poi va in crash in esecuzione con TypeError: Cannot read properties of undefined (reading 'name'). Con strict, il crash diventa un errore di compilazione. Le correzioni sono nel primo blocco di questa pagina.

strictFunctionTypes: perché esiste

Una funzione che gestisce solo stringhe non deve essere usata dove possono arrivare numeri. Il controllo qui sotto è zittito con @ts-expect-error, così puoi eseguirlo e vedere cosa previene l'errore:

Senza il commento, l'assegnazione è l'errore TS2322, Type '(s: string) => void' is not assignable to type 'Handler'., seguito da Types of parameters 's' and 'value' are incompatible. Resta un'eccezione voluta: i parametri dei metodi dichiarati con la sintassi dei metodi (handle(value: string | number): void dentro un'interfaccia) vengono ancora controllati in modo più permissivo, quindi shout si potrebbe assegnare a un metodo del genere senza errori.

strictPropertyInitialization

Ogni campo di classe deve ricevere un valore nella dichiarazione o nel costruttore. Tre modi per soddisfare il controllo:

Output:

Account {
  owner: 'Ada',
  balance: 0,
  history: [],
  lastLogin: undefined,
  sessionId: 's-1'
}

Le proprietà lastLogin e sessionId esistono con il valore undefined perché con target ES2022 i campi di classe sono veri campi JavaScript. Il ! elimina il controllo senza aggiungere alcuna protezione in esecuzione, quindi preferisci le altre forme. Questa opzione richiede strictNullChecks: se disattivi quella, si disattiva anche questa.

Attivare strict in un progetto esistente

Passare una codebase grande a strict tutto in una volta può produrre centinaia di errori. Dato che strict è il default di TypeScript 7, aggiornare un progetto il cui tsconfig.json non ha mai menzionato strict lo attiva da solo; scrivi "strict": false se ti serve il vecchio comportamento durante la migrazione. Un percorso che mantiene la build verde:

  1. Aggiungi "strict": true e disattiva le opzioni con più errori, di solito "strictNullChecks": false e "noImplicitAny": false.
  2. Correggi gli errori rimasti, poi attiva un'altra opzione e ripeti.
  3. Per noImplicitAny, la maggior parte delle correzioni sono annotazioni sui parametri. Per strictNullChecks, aggiungi | undefined dove i valori possono mancare, poi gestiscilo con ?., ?? o un controllo if.
  4. Dove una correzione deve aspettare, metti sulla riga // @ts-expect-error con un motivo. A differenza di @ts-ignore, segnala un errore quando il problema sparisce, così la lista si accorcia da sola.

Non usare as any o ! per zittire gli errori in blocco: ognuno nasconde proprio il bug che l'opzione doveva trovare.

Opzioni utili che strict non include

Sono separate perché rifiutano codice che spesso è corretto. Molti progetti le attivano comunque.

OpzioneCosa fa
noUncheckedIndexedAccessarr[i] e record[key] includono undefined nel loro tipo
exactOptionalPropertyTypesdebug?: boolean accetta una chiave mancante ma non debug: undefined
noImplicitReturnsogni percorso di una funzione che restituisce un valore deve fare return (TS7030)
noImplicitOverrideun metodo che sovrascrive un metodo della classe base deve dire override (TS4114)
noFallthroughCasesInSwitchun case non vuoto deve terminare con break, return o throw (TS7029)
noUnusedLocals, noUnusedParametersvariabili e parametri inutilizzati sono errori
noPropertyAccessFromIndexSignaturele chiavi di una index signature devono usare obj["key"], non obj.key

noUncheckedIndexedAccess è quella che intercetta più bug reali. Con l'opzione attiva:

const scores = [90, 85];
const d: Record<string, number> = {};

const third: number = scores[2]; // error TS2322: Type 'number | undefined' is not assignable to type 'number'.
const c: number = d["x"];        // same error

const safe = scores[2] ?? 0;     // number
for (const s of scores) {        // for...of is not affected: s is number
    console.log(s);
}

In TypeScript 7, tsc --init attiva noUncheckedIndexedAccess e exactOptionalPropertyTypes nella configurazione che genera, accanto a strict.

Domande frequenti

Cosa fa lo strict mode in TypeScript?

"strict": true attiva un gruppo di controlli più severi: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis, useUnknownInCatchVariables e strictBuiltinIteratorReturn. Insieme impediscono che any compaia in silenzio e fanno entrare null e undefined nel sistema dei tipi.

Lo strict mode è attivo di default in TypeScript?

In TypeScript 7 sì: strict vale true di default, quindi un progetto senza alcuna impostazione strict riceve tutti i controlli strict. Anche tsc --init scrive "strict": true in modo esplicito. Per disattivarlo devi scrivere "strict": false.

Posso disattivare un solo controllo strict e tenere gli altri?

Sì. Le singole opzioni hanno la precedenza su strict: { "strict": true, "strictNullChecks": false } mantiene tutti i controlli strict tranne quello su null. È il modo abituale per migrare una codebase grande un'opzione alla volta.

Lo strict mode di TypeScript è lo stesso di "use strict" in JavaScript?

No. "use strict" è una modalità di esecuzione di JavaScript che cambia il comportamento del codice. Lo strict di TypeScript cambia solo ciò che segnala il type checker. TypeScript 7 emette sempre "use strict" nell'output non modulare, e alwaysStrict: false è ora un'opzione rimossa.

strict include noUncheckedIndexedAccess?

No. noUncheckedIndexedAccess, exactOptionalPropertyTypes, noImplicitReturns, noImplicitOverride e noFallthroughCasesInSwitch sono opzioni separate che attivi tu. tsc --init attiva le prime due nella configurazione che genera.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA