Come sopprimere "errore TS2533: l'oggetto è probabilmente" null "o" non definito ""?


226

Ho un type:

type tSelectProtected = {
  handleSelector?: string,
  data?: tSelectDataItem[],

  wrapperEle?: HTMLElement,
  inputEle?: HTMLElement,
  listEle?: HTMLElement,
  resultEle?: HTMLElement,

  maxVisibleListItems?: number
}

Dichiaro una variabile globale a livello di modulo:

var $protected : tSelectProtected = {};

Sto assegnando il valore corretto function1()nell'ambito:

$protected.listEle = document.createElement('DIV');

Più tardi function2()nell'ambito, sto chiamando:

$protected.listEle.classList.add('visible');

Ricevo l'errore TypeScript:

error TS2533: Object is possibly 'null' or 'undefined'

So che posso fare un controllo esplicito usando if ($protected.listEle) {$protected.listEle}per calmare il compilatore, ma questo sembra essere molto sfortunato per la maggior parte dei casi non banali.

Come può o deve essere gestita questa situazione senza disabilitare i controlli del compilatore TS?

Risposte:


99

Questa funzione è chiamata "controlli null rigorosi", per disattivarla assicurarsi che il --strictNullChecksflag del compilatore non sia impostato.

Tuttavia, l'esistenza di nullè stata descritta come L'errore di miliardi di dollari , quindi è eccitante vedere linguaggi come TypeScript che introducono una correzione. Consiglio vivamente di tenerlo acceso.

Un modo per risolvere questo problema è assicurarsi che i valori non siano mai nullo undefined, ad esempio inizializzandoli in anticipo:

interface SelectProtected {
    readonly wrapperElement: HTMLDivElement;
    readonly inputElement: HTMLInputElement;
}

const selectProtected: SelectProtected = {
    wrapperElement: document.createElement("div"),
    inputElement: document.createElement("input")
};

Vedi la risposta di Ryan Cavanaugh per un'opzione alternativa, però!


8
Personalmente uso nulls in JavaScript "vanilla" per inizializzare variabili o valori di proprietà. Questo mi dà una risposta chiara se esiste var o prop dato ma non ha ancora "nessun valore utilizzabile" o "il valore è stato cancellato in qualche punto di esecuzione". È solo per convenzione. Questo potrebbe non essere il miglior approccio in TypeScript, come posso vedere dalle risposte qui. Grazie per i tuoi pensieri
Grasnal

26
Anche l'inizializzazione non sopprime "L'oggetto è forse 'indefinito'" per me in TS 2.7.2
Tyguy7,

1
Sì, ma queste definizioni modificano i valori degli oggetti, ad esempio HTMLDivElement non ha target più vicino e altri eventi e proprietà degli elementi di base.
Clarence,

5
Cosa succede se si sta tentando di descrivere uno stato di una proprietà dell'oggetto Javascript, in cui si trova la rappresentazione reale dello stato iniziale null?
Timur Mamedov

1
Aggiungendo che è !disponibile un operatore, molto simile a quelli di Kotlin che ti consente di rendere questi controlli molto più concisi
Alvaro,

601

Se sai da esterno significa che un'espressione non lo è null o undefined, puoi usare l'operatore di asserzione non nullo !per eliminare quei tipi:

// Error, some.expr may be null or undefined
let x = some.expr.thing;
// OK
let y = some.expr!.thing;

12
Grazie per avermi informato ! - Non-null assertion operatordell'operatore. Sembra che la cosa non sia ancora ben documentata ( https://github.com/Microsoft/TypeScript/issues/11494 ), quindi chiunque cerchi risposte leggi questo http://stackoverflow.com/questions/38874928/operator-in-typescript -after-object-method
grasnal

9
anche questo non ha alcun effetto per me su tsc v2.7.2
Tyguy7,

6
@ThomasSauvajon l' !operatore qui non fa la stessa cosa ?di C #! È solo un'asserzione di sistema di tipo ; non provocherà l'arresto anomalo del programma durante il tentativo di leggere una proprietà da nullo undefined.
Ryan Cavanaugh,

2
Dal manuale, aggiunto al pungolo di Ryan: La sintassi è postfissa !: identifier!rimuove nulle undefineddal tipo diidentifier Questo è quello che Ryan ha già detto, ma trovo che sia utile anche in questo modo.
John Hatton,

6
Questo non funziona in Typescript 3.2.2. È stato rimosso?
Lars Nyström,

25

Ero solito:

if (object !== undefined) {
    // continue - error suppressed when used in this way.
}

In alternativa, puoi usare la coercizione di tipo:

const objectX = object as string

Tuttavia, prima di scegliere una delle soluzioni alternative sopra descritte, ti preghiamo di considerare l'architettura a cui stai mirando e il suo impatto sul quadro generale.


57
per qualche motivo il mio TSC ignora che se la dichiarazione, la considera ancora probabilmente indefinita ...
Tyguy7

9
il mio errore NON viene soppresso quando usoif(object!==undefined) object.function();
Jérémy

Si può anche usare il doppio confronto con nulle undefined, e non è una cattiva pratica (solo se si usa con quei due tipi) - l'evento TSLint ti permetterà di farlo. Facilita il controllo se qualcosa è definito perché invece di scrivere null !== someObject && undefined !== someObjectpuoi usare solonull != someObject
Marecky

15

Non una risposta diretta alla domanda del PO, ma nel mio caso avevo la seguente configurazione:

Carattere tipografico - v3.6.2
tslint -v5.20.0

E usando il seguente codice

const refToElement = useRef(null);

if (refToElement && refToElement.current) {
     refToElement.current.focus(); // Object is possibly 'null' (for refToElement.current)
}

Sono passato sopprimendo il compilatore per quella riga. Si noti che poiché si tratta di un errore del compilatore e non dell'errore di linter, // tslint:disable-next-linenon ha funzionato. Inoltre, secondo la documentazione, questo dovrebbe essere usato raramente, solo quando necessario -

const refToElement = useRef(null);

if (refToElement && refToElement.current) {
     // @ts-ignore: Object is possibly 'null'.
     refToElement.current.focus(); 
}

AGGIORNARE :

Con Typescript 3.7, è possibile utilizzare il concatenamento opzionale per risolvere il problema sopra indicato come -

refToElement?.current?.focus();

2
Soluzione molto migliore della disabilitazione di strictNullChecks, si dovrebbe usare cautela con questo, il più delle volte si desidera l'errore di riferimento null perché può causare mal di testa reali lungo la strada.
Andy Braham,

La proprietà 'getBoundingClientRect' non esiste sul tipo 'never'.
mqliutie

Nel mio caso questo concatenamento opzionale non ha funzionato. const input = useRef<HTMLInputElement>(null);e ha if (input && input.current) { input.current.value = ''; }fatto il trucco.
Timo,

13

Questa soluzione ha funzionato per me:

  • vai su tsconfig.json e aggiungi "strictNullChecks": false

inserisci qui la descrizione dell'immagine


Questo ha funzionato anche per me. Sebbene continui a dare un errore come, ad esempio, nelle istruzioni di iscrizione, non riconosce la variabile di risultato, typescript vuole che dichiari .subscribe (result => this.result = result.json ());
Aarchie,

Hai provato a utilizzare l'operatore 'map'? Google "rxjs / map". Fondamentalmente faccio :. Http.get (...). Map (result => result.json ()). Iscriviti (risultato => {fai le tue cose qui})
Mahesh Nepal

38
non risponde alla domanda. OP ha detto esplicitamente: "senza disabilitare i controlli del compilatore TS"
pvill

4
Qual è lo scopo di utilizzare TypeScript e rimuovere l'errore di linter per avvisarti? Penso che l'opzione migliore sia lanciare il valore desiderato asse sei sicuro al 100%. Ho ottenuto il caso con mongodb e il valore restituito FindOneOrUpdate e ho dovuto inviarlo allo schema perché result.valueè stato dichiarato come TSchema | undefinede ho già verificato result.okprima
Vincent

12

Se sai che il tipo non sarà mai nullo undefined, dovresti dichiararlo foo: Barsenza ?. Dichiarare un tipo con il? Bar sintassi significa che potrebbe essere indefinito, il che è qualcosa da verificare.

In altre parole, il compilatore sta facendo esattamente quello che gli stai chiedendo. Se vuoi che sia facoltativo, dovrai controllare in seguito.


1
"il compilatore sta facendo esattamente quello che gli stai chiedendo" quindi la mia idea è sbagliata, grazie. Devo cambiare approccio un po '.
Grasnal

Nel mio caso il compilatore semplicemente non si rendeva conto che avevo già controllato l'oggetto per null. Ho un getter che verifica la presenza di null e lo chiama getter. Quindi no, non sta facendo esattamente quello che gli ho chiesto (questo non vuol dire che mi aspetto che capisca tutto).
CWagner,

9

Questo non è un problema dell'OP, ma ho ricevuto lo stesso Object is possibly 'null'messaggio quando avevo dichiarato per errore un parametro come tipo null:

something: null;

invece di assegnargli il valore null:

something: string = null;

2
Questa è la risposta effettiva. Frustrante quando si esegue un controllo null esplicito effettivo e si ottiene ancora un Object is possibly 'null'errore. Questa risposta risolve questo.
Ben Racicot,

5

Come opzione, puoi usare un tipo casting. Se si verifica questo errore da dattiloscritto significa che alcune variabili hanno tipo o non sono definite:

let a: string[] | undefined;

let b: number = a.length; // [ts] Object is possibly 'undefined'
let c: number = (a as string[]).length; // ok

Assicurati che aesista davvero nel tuo codice.



2

Suggerimento per RxJS

Avrò spesso variabili membro di tipo Observable<string>e non lo inizializzerò fino a quando ngOnInit(usando Angular). Il compilatore presuppone quindi che non sia inizializzato perché non è "assegnato in modo definitivo nel costruttore" - e il compilatore non capirà maingOnInit .

È possibile utilizzare l' !operatore di asserzione sulla definizione per evitare l'errore:

favoriteColor!: Observable<string>;

Un osservabile non inizializzato può causare tutti i tipi di problemi di runtime con errori come "devi fornire un flusso ma hai fornito null". La !va bene se sicuramente sa che sta per essere impostato in qualcosa di similengOnInit , ma ci possono essere casi in cui il valore è impostato in qualche altro meno deterministica modo.

Quindi un'alternativa che a volte userò è:

public loaded$: Observable<boolean> = uninitialized('loaded');

Dove uninitializedè definito a livello globale da qualche parte come:

export const uninitialized = (name: string) => throwError(name + ' not initialized');

Quindi, se si utilizza mai questo flusso senza che sia stato definito, verrà immediatamente generato un errore di runtime.


Non consiglio di farlo dappertutto, ma a volte lo farò - specialmente se mi affido ai parametri @Input impostati dall'esterno
Simon_Weaver

2

In ReactJS, controllo nel costruttore se le variabili sono nulle, se lo sono la tratto come un'eccezione e gestisco l'eccezione in modo appropriato. Se le variabili non sono nulle, il codice continua e il compilatore non si lamenta più dopo quel punto:

private variable1: any;
private variable2: any;

constructor(props: IProps) {
    super(props);

    // i.e. here I am trying to access an HTML element
    // which might be null if there is a typo in the name
    this.variable1 = document.querySelector('element1');
    this.variable2 = document.querySelector('element2');

    // check if objects are null
    if(!this.variable1 || !this.variable2) {
        // Manage the 'exception', show the user a message, etc.
    } else {
        // Interpreter should not complain from this point on
        // in any part of the file
        this.variable1.disabled = true; // i.e. this line should not show the error
    }

1

Mi sono imbattuto in questo con React durante l'impostazione dello stato e l'utilizzo map.

In questo caso stavo effettuando una chiamata di recupero API e il valore della risposta non era noto, ma avrei dovuto avere un valore "Rispondi". Ho usato un tipo personalizzato per questo, ma poiché il valore potrebbe essere null, ho comunque ricevuto un errore TS. Consentire al tipo di essere nullnon lo risolve; in alternativa puoi usare un default parameter value, ma questo è stato disordinato per il mio caso.

L'ho superato fornendo un valore predefinito nel caso in cui la risposta fosse vuota usando solo un operatore ternario:

this.setState({ record: (response.Answer) ? response.Answer : [{ default: 'default' }] });

0

In dattiloscritto è possibile effettuare le seguenti operazioni per sopprimere error:

let subString?: string;

subString > !null; - Nota il punto esclamativo aggiunto prima di null.


0

Prova a chiamare l'oggetto in questo modo:

(<any>Object).dosomething

Questo errore si è verificato perché li hai dichiarati come utilizzo facoltativo ?. Ora Typescript fa un controllo rigoroso e non consentirà di fare qualsiasi cosa possa essere undefined. Pertanto, è possibile utilizzare (<any>yourObject)qui.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.