Wie kann man "Fehler TS2533: Objekt ist möglicherweise 'null' oder 'undefiniert'" unterdrücken?


225

Ich habe eine type:

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

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

  maxVisibleListItems?: number
}

Ich deklariere eine globale modulweise Variable:

var $protected : tSelectProtected = {};

Ich weise im function1()Bereich den richtigen Wert zu :

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

Später function2()rufe ich an:

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

Ich erhalte einen TypeScript-Fehler:

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

Ich weiß, dass ich explizite Überprüfungen durchführen kann if ($protected.listEle) {$protected.listEle}, um den Compiler zu beruhigen, aber dies scheint für die meisten nicht trivialen Fälle sehr unhandlich zu sein.

Wie kann oder sollte mit dieser Situation umgegangen werden, ohne die TS-Compilerprüfungen zu deaktivieren?

Antworten:


99

Diese Funktion wird als "strikte Nullprüfung" bezeichnet, um sicherzustellen, dass das --strictNullChecksCompiler-Flag nicht gesetzt ist.

Die Existenz von nullwurde jedoch als " Der Milliarden-Dollar-Fehler" beschrieben. Daher ist es aufregend zu sehen, wie Sprachen wie TypeScript einen Fix einführen. Ich würde dringend empfehlen, es eingeschaltet zu lassen.

Eine Möglichkeit, dies zu beheben, besteht darin, sicherzustellen, dass die Werte niemals nullvorliegen undefined, oder indem Sie sie beispielsweise im Voraus initialisieren:

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

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

Siehe Ryan Cavanaughs Antwort für eine alternative Option!


8
Persönlich verwende ich nulls in "Vanilla" JavaScript, um Variablen oder Eigenschaftswerte zu initialisieren. Dies gibt mir eine klare Antwort, wenn var oder prop vorhanden ist, aber "noch kein verwendbarer Wert" vorliegt oder "der Wert zu einem bestimmten Zeitpunkt der Ausführung gelöscht wurde". Es ist nur durch Konvention. Dies ist möglicherweise nicht der beste Ansatz in TypeScript, wie ich anhand der Antworten hier sehen kann. Danke für deine Gedanken.
Grasnal

25
Selbst die Initialisierung unterdrückt nicht "Objekt ist möglicherweise 'undefiniert'" für mich in TS 2.7.2
Tyguy7

1
Ja, aber diese Definitionen ändern die Werte der Objekte. Beispielsweise verfügt HTMLDivElement nicht über das nächstgelegene Ziel und andere grundlegende Elementereignisse und -eigenschaften.
Clarence

5
Was ist, wenn Sie versuchen, einen Status einer Javascript-Objekteigenschaft zu beschreiben, in dem die wahre Darstellung des Startstatus vorliegt null?
Timur Mamedov

1
Hinzu kommt, dass ein !Operator verfügbar ist, der dem in Kotlin sehr ähnlich ist, mit dem Sie diese Überprüfungen viel präziser durchführen können
Alvaro

598

Wenn Sie von außen wissen, dass ein Ausdruck nicht nulloder ist undefined, können Sie den Nicht-Null-Assertionsoperator verwenden !, um diese Typen zu erzwingen:

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

12
Vielen Dank, dass Sie mich über den ! - Non-null assertion operatorBetreiber informiert haben . Es scheint, dass die Sache noch nicht gut dokumentiert ist ( https://github.com/Microsoft/TypeScript/issues/11494 ). Wer also Antworten sucht, liest diese http://stackoverflow.com/questions/38874928/operator-in-typescript -nach-Objekt-Methode
Grasnal

9
Dies hat auch keine Auswirkungen auf mich auf tsc v2.7.2
Tyguy7

6
@ThomasSauvajon der !Operator hier macht nicht das Gleiche wie ?in C #! Es ist nur eine Typsystembehauptung ; Es wird nicht dazu führen, dass Ihr Programm nicht abstürzt, wenn Sie versuchen, eine Eigenschaft von nulloder zu lesen undefined.
Ryan Cavanaugh

2
Aus dem Handbuch, das bei Ryans Prodding hinzugefügt wurde: Die Syntax lautet postfix !: identifier!remove nullund undefinedfrom the type ofidentifier Dies ist, was Ryan bereits gesagt hat, aber ich finde diesen Weg auch hilfreich.
John Hatton

5
Dies funktioniert in Typescript 3.2.2 nicht. Wurde es entfernt?
Lars Nyström

25

Ich benutzte:

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

Alternativ können Sie auch Zwang anwenden:

const objectX = object as string

Bevor Sie sich jedoch für eine der oben genannten Problemumgehungen entscheiden, sollten Sie die angestrebte Architektur und deren Auswirkungen auf das Gesamtbild berücksichtigen.


57
Aus irgendeinem Grund ignoriert mein TSC diese if-Anweisung und betrachtet sie immer noch als möglicherweise undefiniert ...
Tyguy7

9
Mein Fehler wird NICHT unterdrückt, wenn ich benutzeif(object!==undefined) object.function();
Jérémy

Man kann auch einen doppelten Vergleich mit nullund verwenden undefined, und dies ist keine schlechte Praxis (nur bei Verwendung mit diesen beiden Typen) - Ereignis TSLint ermöglicht es Ihnen, dies zu tun. Es erleichtert die Überprüfung, ob etwas definiert ist, da Sie anstelle des Schreibens null !== someObject && undefined !== someObjectnurnull != someObject
Marecky

14

Keine direkte Antwort auf die Frage des OP, aber in meinem Fall hatte ich das folgende Setup -

Typoskript - v3.6.2
tslint -v5.20.0

Und mit dem folgenden Code

const refToElement = useRef(null);

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

Ich ging weiter, indem ich den Compiler für diese Zeile unterdrückte. Beachten Sie, dass // tslint:disable-next-linedies nicht funktioniert hat , da es sich um einen Compilerfehler und nicht um den Linterfehler handelt . Außerdem sollte dies gemäß der Dokumentation nur selten verwendet werden, wenn dies erforderlich ist -

const refToElement = useRef(null);

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

UPDATE :

Mit Typescript 3.7 können Sie die optionale Verkettung verwenden , um das obige Problem wie folgt zu lösen:

refToElement?.current?.focus();

2
strictNullChecksDies ist eine viel bessere Lösung als das Deaktivieren der . Vorsicht ist geboten. Meistens möchten Sie den Nullreferenzfehler, da dies später zu echten Kopfschmerzen führen kann.
Andy Braham

Die Eigenschaft 'getBoundingClientRect' ist für den Typ 'never' nicht vorhanden.
mqliutie

In meinem Fall hat diese optionale Verkettung nicht funktioniert. const input = useRef<HTMLInputElement>(null);und if (input && input.current) { input.current.value = ''; }tat den Trick.
Timo

13

Diese Lösung hat bei mir funktioniert:

  • Gehen Sie zu tsconfig.json und fügen Sie "strictNullChecks" hinzu: false

Geben Sie hier die Bildbeschreibung ein


Das hat auch bei mir funktioniert. Obwohl es immer noch Fehler gibt, wie zum Beispiel in subscribe-Anweisungen, erkennt es die Ergebnisvariable nicht. Typoskript möchte, dass es .subscribe deklariert (result => this.result = result.json ());
Aarchie

Haben Sie versucht, den Kartenoperator zu verwenden? Google 'rxjs / map'. Ich mache im Grunde: Http.get (...). Map (result => result.json ()). Subscribe (result => {mach deine Sachen hier})
Mahesh Nepal

38
beantwortet die Frage nicht. OP sagte ausdrücklich: "Ohne Deaktivierung der TS-Compiler-Prüfungen"
pvill

4
Was bringt es Ihnen, TypeScript zu verwenden und den Linter-Fehler zu beseitigen, um Sie zu warnen? Ich denke, die bessere Option ist es, den gewünschten Wert mit zu geben, aswenn Sie 100% sicher sind. Ich habe den Fall mit Mongodb und FindOneOrUpdate Rückgabewert und ich musste es in das Schema umwandeln, weil das result.valueals deklariert ist TSchema | undefinedund ich bereits result.okvorher mit
Vincent

12

Wenn Sie wissen, dass der Typ niemals nulloder sein wird undefined, sollten Sie ihn als foo: Barohne den deklarieren ?. Wenn Sie einen Typ mit der ? BarSyntax deklarieren, kann dies möglicherweise undefiniert sein. Dies müssen Sie überprüfen.

Mit anderen Worten, der Compiler macht genau das, was Sie von ihm verlangen. Wenn Sie möchten, dass es optional ist, müssen Sie dies später überprüfen.


1
"Der Compiler macht genau das, worum Sie es bitten", also ist meine Idee falsch, danke. Ich muss den Ansatz ein wenig ändern.
Grasnal

In meinem Fall hat der Compiler einfach nicht bemerkt, dass ich das Objekt bereits auf null überprüft habe. Ich habe einen Getter, der nach Null sucht und diesen Getter aufruft. Also nein, es macht nicht genau das, was ich gefragt habe (das heißt nicht, ich erwarte, dass es alles herausfindet).
CWagner

9

Dies ist nicht das Problem des OP, aber ich habe dieselbe Object is possibly 'null'Meldung erhalten, als ich versehentlich einen Parameter als Nulltyp deklariert hatte:

something: null;

anstatt ihm den Wert null zuzuweisen:

something: string = null;

2
Dies ist die eigentliche Antwort. Frustrierend, wenn Sie eine tatsächliche explizite Nullprüfung durchführen und trotzdem einen Object is possibly 'null'Fehler erhalten. Diese Antwort löst das.
Ben Racicot

5

Optional können Sie einen Typ Casting verwenden. Wenn Sie diesen Fehler vom Typoskript haben, bedeutet dies, dass eine Variable einen Typ hat oder undefiniert ist:

let a: string[] | undefined;

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

Stellen Sie sicher, dass dies awirklich in Ihrem Code vorhanden ist.



2

Tipp für RxJS

Ich habe oft Mitgliedsvariablen vom Typ Observable<string>, und ich werde sie erst initialisieren ngOnInit(mit Angular). Der Compiler geht dann davon aus, dass es nicht initialisiert ist, da es nicht "definitiv im Konstruktor zugewiesen" ist - und der Compiler wird es nie verstehen ngOnInit.

Sie können den !Assertion-Operator für die Definition verwenden, um den Fehler zu vermeiden:

favoriteColor!: Observable<string>;

Ein nicht initialisiertes Observable kann alle Arten von Laufzeitschmerzen verursachen, mit Fehlern wie "Sie müssen einen Stream bereitstellen, aber Sie haben null angegeben". Das !ist in Ordnung, wenn Sie definitiv wissen, dass es in so etwas wie gesetzt wird ngOnInit, aber es kann Fälle geben, in denen der Wert auf eine andere, weniger deterministische Weise gesetzt wird.

Eine Alternative, die ich manchmal benutze, ist:

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

Wo uninitializedist global irgendwo definiert als:

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

Wenn Sie diesen Stream dann jemals verwenden, ohne dass er definiert ist, wird sofort ein Laufzeitfehler ausgegeben.


Ich empfehle dies nicht überall, aber ich mache es manchmal - besonders wenn ich mich auf von außen eingestellte
@

2

In ReactJS überprüfe ich im Konstruktor, ob die Variablen null sind. Wenn dies der Fall ist, behandle ich sie wie eine Ausnahme und verwalte die Ausnahme entsprechend. Wenn die Variablen nicht null sind, wird der Code fortgesetzt und der Compiler beschwert sich nach diesem Punkt nicht mehr:

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

Ich bin mit React darauf gestoßen, als ich den Status eingestellt und verwendet habe map.

In diesem Fall habe ich einen API-Abruf aufgerufen und der Wert der Antwort war nicht bekannt, sollte aber den Wert "Antwort" haben. Ich habe dafür einen benutzerdefinierten Typ verwendet, aber da der Wert sein könnte null, habe ich trotzdem einen TS-Fehler erhalten. Das Zulassen des Typs nullbehebt das Problem nicht. alternativ könnte man ein verwenden default parameter value, aber das war für meinen Fall chaotisch.

Ich habe es überwunden, indem ich einen Standardwert für den Fall angegeben habe, dass die Antwort leer war, indem ich nur einen ternären Operator verwendet habe:

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

0

Im Typoskript können Sie Folgendes tun, um Folgendes zu unterdrücken error:

let subString?: string;

subString > !null; - Beachten Sie das hinzugefügte Ausrufezeichen vor null.


0

Versuchen Sie, ein Objekt wie folgt aufzurufen:

(<any>Object).dosomething

Dieser Fehler ist aufgetreten, weil Sie sie mit als optional deklariert haben ?. Jetzt führt Typescript eine strenge Prüfung durch und erlaubt nichts, was möglich ist undefined. Daher können Sie (<any>yourObject)hier verwenden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.