C'è un modo per controllare sia `null` che` undefined`?


382

Poiché TypeScript è fortemente tipizzato, è sufficiente utilizzarlo if () {}per controllare nulle undefinednon suona bene.

TypeScript ha qualche funzione dedicata o zucchero sintattico per questo?


9
Since TypeScript is strongly-typedNon sono riuscito a trovarlo nei suoi documenti e ne dubito ...
pawciobiel,

3
Consiglio di leggere gli ultimi tipi non annullabili, questo è Typescript 2, ma già in beta da oggi. [Tipi non annullabili # 7140] ( github.com/Microsoft/TypeScript/pull/7140 )
RyBolt

2
TypeScript non ha funzioni dedicate per fare nulla. È un sistema di battitura e un transpiler, non una libreria.

Risposte:


378

Utilizzando un controllo di giocoleria, puoi testare entrambi nulle undefinedin un colpo solo:

if (x == null) {

Se si utilizza un controllo rigoroso, sarà vero solo per i valori impostati su nulle non verrà valutato come vero per le variabili non definite:

if (x === null) {

Puoi provare questo con vari valori usando questo esempio:

var a: number;
var b: number = null;

function check(x, name) {
    if (x == null) {
        console.log(name + ' == null');
    }

    if (x === null) {
        console.log(name + ' === null');
    }

    if (typeof x === 'undefined') {
        console.log(name + ' is undefined');
    }
}

check(a, 'a');
check(b, 'b');

Produzione

"a == null"

"a non è definito"

"b == null"

"b === null"


52
Che cos'è il "controllo giocoleria"?
kolobok,

18
@akapelko è dove si manipola il tipo (cioè "possiamo rendere questo tipo un valore booleano"). Quindi una stringa vuota viene trattata come un falso booleano, ad esempio. Un bug comune quando si destreggia è: "false" == falseuna stringa non vuota come "false" valuta true.
Fenton,

12
Ciò è dovuto alla "coercizione del tipo" di JS.
Astravagrant

Tranne se x è 0 (e questo è un valore valido), passerà il test indefinito / null.
Jon Gunter,

3
@JonGunter sarebbe vero per i if(x)controlli di stile di verità / falsità , ma non if(x == null), che cattura solo nulle undefined. Verificare che var c: number = 0; check(c, 'b');non sia "nully" null, oppure undefined.
Fenton,

270
if( value ) {
}

valuterà truese valuenon è:

  • null
  • undefined
  • NaN
  • stringa vuota ''
  • 0
  • false

dattiloscritto include regole javascript.


12
Cosa succede se il valore è di tipo booleano?
ianstigator,

puoi combinare due variabili ad es. se (valore1 && valore2) verifica se entrambi non sono definiti?
ARK,

8
@ RamazanSağır sì, lo so, ma il fatto è 0 valore è qualcosa di valido che posso avere, l'unico controllo che voglio fare è che la variabile non è né nulla né indefinito. Ho letto che posso farlo usando val! = Null (il! = Anziché! == controlla anche il valore indefinito)
Alex

4
Questa soluzione non funzionerà se la regola tslint - "espressioni booleane rigorose" è abilitata.
ip_x,

1
Valuterà falso se ci valorizzi falsamente, semplice come questo.
Ayfri,

50

TypeScript ha una funzione o una sintassi dedicata per questo

TypeScript comprende appieno la versione di JavaScript che è something == null.

TypeScript escluderà correttamente entrambi nulle undefinedcon tali controlli.

Di Più

https://basarat.gitbook.io/typescript/recap/null-undefined


1
Mi piace fare due uguali myVar == null. Solo un'altra opzione.
David Sherret,

30
== nullè il modo corretto di verificare null e undefined. !!somethingè una coercizione inutile in un condizionale in JS (basta usare something). !!somethingforzerà anche 0 e "" su falso, che non è quello che vuoi fare se stai cercando null / indefinito.
C Snover,

39

Ho fatto diversi test nel parco giochi dattiloscritto:

http://www.typescriptlang.org/play/

let a;
let b = null;
let c = "";
var output = "";

if (a == null) output += "a is null or undefined\n";
if (b == null) output += "b is null or undefined\n";
if (c == null) output += "c is null or undefined\n";
if (a != null) output += "a is defined\n";
if (b != null) output += "b is defined\n";
if (c != null) output += "c is defined\n";
if (a) output += "a is defined (2nd method)\n";
if (b) output += "b is defined (2nd method)\n";
if (c) output += "c is defined (2nd method)\n";

console.log(output);

dà:

a is null or undefined
b is null or undefined
c is defined

così:

  • controllando se (a == null) è giusto sapere se a è null o non definito
  • controllando se (a! = null) è giusto sapere se a è definito
  • verificare se (a) è errato per sapere se a è definito

1
Perché dovresti usare il parco giochi TypeScript per questo? Niente qui ha qualcosa a che fare con TypeScript.

10
Poiché la domanda era correlata a Typescript, stavo cercando di testare diverse soluzioni proposte contro il transpiler Typescript.
Juangui Jordán,

6
Il transpiler TS non trasformerebbe affatto questo codice.

31

Penso che questa risposta abbia bisogno di un aggiornamento, controlla la cronologia delle modifiche per la vecchia risposta.

Fondamentalmente, hai tre casi differiti nulli, indefiniti e non dichiarati, vedi lo snippet di seguito.

// bad-file.ts
console.log(message)

Verrà visualizzato un errore che indica che la variabile messagenon è definita (ovvero non dichiarata), ovviamente, il compilatore Typescript non dovrebbe lasciarti fare, ma DAVVERO nulla può impedirti.

// evil-file.ts
// @ts-gnore
console.log(message)

Il compilatore sarà felice di compilare il codice sopra. Quindi, se sei sicuro che tutte le variabili sono dichiarate, puoi semplicemente farlo

if ( message != null ) {
    // do something with the message
}

il codice sopra verificherà nulle undefined, MA nel caso in cui la messagevariabile possa essere dichiarata (per sicurezza), si può considerare il seguente codice

if ( typeof(message) !== 'undefined' && message !== null ) {
    // message variable is more than safe to be used.
}

Nota: l'ordine qui typeof(message) !== 'undefined' && message !== nullè molto importante, devi prima verificare lo undefinedstato per prima cosa sarà lo stesso message != null, grazie a @Jaider.


4
M. Kamal se qualcosa = 0, la tua verifica con! Qualcosa ti darà problemi.
justcode del

1
@arturios puoi per favore farmi un esempio !!
Ahmed Kamal,

2
@arturios Ma 0 è già un valore falso in JavaScript !! quindi qual è il punto qui?
Ahmed Kamal,

1
@ Al-un no, vederlo in azione qui
Ahmed Kamal

1
la versione aggiornata è sbagliata. La prima cosa da controllare dovrebbe essere indefinita ... come:if(typeof something !== 'undefined' && something !== null){...}
Jaider

27

In TypeScript 3.7 ora abbiamo il concatenamento opzionale e Nullish Coalescing per controllare contemporaneamente null e indefinito , ad esempio:

let x = foo?.bar.baz();

questo codice verificherà se è stato definito foo, altrimenti tornerà indefinito

vecchio modo :

if(foo != null && foo != undefined) {
   x = foo.bar.baz();
} 

Questo:

let x = (foo === null || foo === undefined) ? undefined : foo.bar();

if (foo && foo.bar && foo.bar.baz) { // ... }

Con il concatenamento opzionale sarà:

let x = foo?.bar();

if (foo?.bar?.baz) { // ... }

un'altra nuova funzionalità è Nullish Coalescing , ad esempio:

let x = foo ?? bar(); // return foo if it's not null or undefined otherwise calculate bar

vecchio modo:

let x = (foo !== null && foo !== undefined) ?
foo :
bar();

3
Questa dovrebbe essere la risposta accettata ora. Typescript 3.7 supporta anche "Nullish Coalescing". var foo = possibleUndefinedOrNull ?? fallbackValueIfFirstValueIsUndefinedOrNull; Ecco la documentazione: typescriptlang.org/docs/handbook/release-notes/…
tkd_aj

23

Potresti provare

if(!!someValue)

con !!.

Spiegazione

Il primo !trasformerà la tua espressione in un booleanvalore.

Quindi !someValueè truese someValueè falsa e falsese someValueè verità . Questo potrebbe essere fonte di confusione.

Aggiungendone un altro !, l'espressione è ora truese someValueè vera e falsese someValueè falsa , che è molto più facile da gestire.

Discussione

Ora, perché mi preoccupo if (!!someValue)quando qualcosa del genere if (someValue)mi avrebbe dato lo stesso risultato?

Perché !!someValueè proprio un'espressione booleana, mentre someValuepotrebbe essere assolutamente qualsiasi cosa. Questo tipo di espressione ora consentirà di scrivere funzioni (e Dio ne abbiamo bisogno) come:

isSomeValueDefined(): boolean {
  return !!someValue
}

invece di:

isSomeValueDefined(): boolean {
  if(someValue) {
    return true
  }
  return false
}

Spero possa essere d'aiuto.


quindi, se someValue è 'false' (con tipo stringa), allora !! someValue è false (tipo booleano)?
Paul Cheung,

Immagino che tu possa dirlo. Questa tecnica è usata esattamente per evitare questo tipo di confusione. Spero vi piaccia!
avi.elkharrat,

ma ciò che mi confonde è !! 'falso' equivale a vero. Proprio per questo caso, non posso usare questa tecnica.
Paul Cheung,

!!'false'è in atto trueperché 'false'è una stringa valida
avi.elkharrat,

quindi questa tecnica non può coprire questo caso o esiste una soluzione alternativa?
Paul Cheung,

16

Perché Typescript 2.x.xdovresti farlo nel modo seguente (usando la protezione del tipo ):

tl; dr

function isDefined<T>(value: T | undefined | null): value is T {
  return <T>value !== undefined && <T>value !== null;
}

Perché?

In questo modo isDefined()rispetterà il tipo di variabile e il seguente codice saprebbe prendere in considerazione questo check in.

Esempio 1 - controllo di base:

function getFoo(foo: string): void { 
  //
}

function getBar(bar: string| undefined) {   
  getFoo(bar); //ERROR: "bar" can be undefined
  if (isDefined(bar)) {
    getFoo(bar); // Ok now, typescript knows that "bar' is defined
  }
}

Esempio 2 - tipi rispetto:

function getFoo(foo: string): void { 
  //
}

function getBar(bar: number | undefined) {
  getFoo(bar); // ERROR: "number | undefined" is not assignable to "string"
  if (isDefined(bar)) {
    getFoo(bar); // ERROR: "number" is not assignable to "string", but it's ok - we know it's number
  }
}

14
if(data){}

è cattivo!

  • nullo
  • non definito
  • falso
  • ....

2
E se i dati sono di tipo booleano?
ianstigator,

puoi combinare due variabili ad es. se (valore1 && valore2) verifica se entrambi non sono definiti?
ARK,

@ianstigator Un booleano può essere valutato come trueo falsesolo. Se hai un valore booleano con nullun'assegnazione o un undefinedvalore, in entrambi i casi il valore verrà valutato come false.
KBeDev

5

Se si utilizza TypeScript, è un approccio migliore consentire al compilatore di verificare la presenza di valori null e indefiniti (o la loro possibilità), anziché controllarli in fase di esecuzione. (Se si desidera verificare in fase di esecuzione, come indicano molte risposte, basta usare value == null).

Utilizzare l'opzione di compilazione strictNullChecksper indicare al compilatore di soffocare su possibili valori nulli o non definiti. Se si imposta questa opzione, e poi c'è una situazione in cui non desidera consentire null e undefined, è possibile definire il tipo Type | null | undefined.


5

Se si desidera passare tslintsenza impostare strict-boolean-expressionsper allow-null-uniono allow-undefined-union, è necessario utilizzare isNullOrUndefinedda node's utilmodulo o rotolare il proprio:

// tslint:disable:no-null-keyword
export const isNullOrUndefined =
  <T>(obj: T | null | undefined): obj is null | undefined => {
    return typeof obj === "undefined" || obj === null;
  };
// tslint:enable:no-null-keyword

Non esattamente zucchero sintattico ma utile quando le tue regole tslint sono rigide.


1

Una notazione più rapida e più breve per i nullcontrolli può essere:

value == null ? "UNDEFINED" : value

Questa riga equivale a:

if(value == null) {
       console.log("UNDEFINED")
} else {
    console.log(value)
}

Soprattutto quando hai un sacco di nullcontrollo è una bella notazione breve.


1

Ho avuto questo problema e alcune delle risposte funzionano bene, JSma non per TSquesto è il motivo.

//JS
let couldBeNullOrUndefined;
if(couldBeNullOrUndefined == null) {
  console.log('null OR undefined', couldBeNullOrUndefined);
} else {
  console.log('Has some value', couldBeNullOrUndefined);
}

Va tutto bene dato che JS non ha Tipi

//TS
let couldBeNullOrUndefined?: string | null; // THIS NEEDS TO BE TYPED AS undefined || null || Type(string)

if(couldBeNullOrUndefined === null) { // TS should always use strict-check
  console.log('null OR undefined', couldBeNullOrUndefined);
} else {
  console.log('Has some value', couldBeNullOrUndefined);
}

Nel TS se la variabile non è stata definita con nullquando si tenta di verificare la presenza che nulll' tslint| il compilatore si lamenterà.

//tslint.json
...
"triple-equals":[true],
...
 let couldBeNullOrUndefined?: string; // to fix it add | null

 Types of property 'couldBeNullOrUndefined' are incompatible.
      Type 'string | null' is not assignable to type 'string | undefined'.
        Type 'null' is not assignable to type 'string | undefined'.

1

In ritardo per unirmi a questa discussione, ma trovo questo hack JavaScript molto utile per verificare se un valore non è definito

 if(typeof(something) === 'undefined'){
   // Yes this is undefined
 }

1

Di solito eseguo il controllo delle giocoleria come già discusso da Fenton . Per renderlo più leggibile, puoi usare isNil di ramda.

import * as isNil from 'ramda/src/isNil';

totalAmount = isNil(totalAmount ) ? 0 : totalAmount ;

1

In modo dettagliato, se si desidera confrontare SOLO valori nulli e non definiti , utilizzare il seguente codice di esempio come riferimento:

const incomingValue : string = undefined;
const somethingToCompare : string = incomingValue; // If the line above is not declared, TypeScript will return an excepion

if (somethingToCompare == (undefined || null)) {
  console.log(`Incoming value is: ${somethingToCompare}`);
}

Se incomingValue non viene dichiarato, TypeScript dovrebbe restituire un'eccezione. Se questo viene dichiarato ma non definito, console.log()verrà restituito "Il valore in entrata è: non definito". Nota che non stiamo usando l'operatore rigoroso uguale.

Il modo "corretto" (controlla le altre risposte per i dettagli), se incomingValuenon è un booleantipo, valuta solo se il suo valore è vero, questo sarà valutato in base al tipo costante / variabile. Una truestringa deve essere definita esplicitamente come stringa utilizzando l' = ''assegnazione. In caso contrario, verrà valutato come false. Controlliamo questo caso usando lo stesso contesto:

const incomingValue : string = undefined;
const somethingToCompare0 : string = 'Trumpet';
const somethingToCompare1 : string = incomingValue;

if (somethingToCompare0) {
  console.log(`somethingToCompare0 is: ${somethingToCompare0}`); // Will return "somethingToCompare0 is: Trumpet"
}

// Now, we will evaluate the second constant
if (somethingToCompare1) {
  console.log(`somethingToCompare1 is: ${somethingToCompare1}`); // Launched if incomingValue is defined
} else {
  console.log(`somethingToCompare1 is: ${somethingToCompare1}`); // Launched if incomingValue is undefined. Will return "somethingToCompare1 is: undefined"
}

somethingToCompare == (non definito || null). (undefined || null) si risolve in null, quindi è un paragone tra qualcosa da confrontare e null
carlosvini,

@carlosvini Certo, il punto di confronto è essere prolisso e fornire un codice di riferimento. Questa è la ragione del confronto non rigoroso. Lo scopo della risposta è di essere chiaro ed esplicativo.
Modificherò


0

Tutti,

La risposta con il maggior numero di voti non funziona davvero se si lavora con un oggetto. In tal caso, se una proprietà non è presente, il controllo non funzionerà. E quello era il problema nel nostro caso: vedi questo esempio:

var x =
{ name: "Homer", LastName: "Simpson" };

var y =
{ name: "Marge"} ;

var z =
{ name: "Bart" , LastName: undefined} ;

var a =
{ name: "Lisa" , LastName: ""} ;

var hasLastNameX = x.LastName != null;
var hasLastNameY = y.LastName != null;
var hasLastNameZ = z.LastName != null;
var hasLastNameA = a.LastName != null;



alert (hasLastNameX + ' ' + hasLastNameY + ' ' + hasLastNameZ + ' ' + hasLastNameA);

var hasLastNameXX = x.LastName !== null;
var hasLastNameYY = y.LastName !== null;
var hasLastNameZZ = z.LastName !== null;
var hasLastNameAA = a.LastName !== null;

alert (hasLastNameXX + ' ' + hasLastNameYY + ' ' + hasLastNameZZ + ' ' + hasLastNameAA);

Risultato:

true , false, false , true (in case of !=)
true , true, true, true (in case of !==) => so in this sample not the correct answer

collegamento plunkr: https://plnkr.co/edit/BJpVHD95FhKlpHp1skUE


Questo non è un buon test. Nessuno di questi valori è rigorosamente null . Prova questo: plnkr.co/edit/NfiVnQNes1p8PvXd1fCG?p=preview
simonhamp

0

Poiché TypeScript è un superset tipizzato di ES6 JavaScript. E lodash sono una libreria di javascript.

L'utilizzo di lodash per verificare se il valore è nullo o indefinito può essere eseguito utilizzando _.isNil().

_.isNil(value)

argomenti

valore (*): il valore da verificare.

ritorna

(booleano) : restituisce vero se il valore è nullo, altrimenti falso.

Esempio

_.isNil(null);
// => true

_.isNil(void 0);
// => true

_.isNil(NaN);
// => false

collegamento

Lodash Docs


1
Perché questo metodo è -2? Lodash non è bravo con lo script di tipo?
Thomas Poignant,

0

attenzione se si utilizza l'archiviazione locale, è possibile finire con la stringa non definita anziché con il valore non definito:

localStorage.setItem('mykey',JSON.stringify(undefined));
localStorage.getItem('mykey') === "undefined"
true

Le persone potrebbero trovarlo utile: https://github.com/angular/components/blob/master/src/cdk/coercion/boolean-property.spec.ts

/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */

/** Coerces a data-bound value (typically a string) to a boolean. */
export function coerceBooleanProperty(value: any): boolean {
  return value != null && `${value}` !== 'false';
}

import {coerceBooleanProperty} from './boolean-property';

describe('coerceBooleanProperty', () => {

  it('should coerce undefined to false', () => {
    expect(coerceBooleanProperty(undefined)).toBe(false);
  });

  it('should coerce null to false', () => {
    expect(coerceBooleanProperty(null)).toBe(false);
  });

  it('should coerce the empty string to true', () => {
    expect(coerceBooleanProperty('')).toBe(true);
  });

  it('should coerce zero to true', () => {
    expect(coerceBooleanProperty(0)).toBe(true);
  });

  it('should coerce the string "false" to false', () => {
    expect(coerceBooleanProperty('false')).toBe(false);
  });

  it('should coerce the boolean false to false', () => {
    expect(coerceBooleanProperty(false)).toBe(false);
  });

  it('should coerce the boolean true to true', () => {
    expect(coerceBooleanProperty(true)).toBe(true);
  });

  it('should coerce the string "true" to true', () => {
    expect(coerceBooleanProperty('true')).toBe(true);
  });

  it('should coerce an arbitrary string to true', () => {
    expect(coerceBooleanProperty('pink')).toBe(true);
  });

  it('should coerce an object to true', () => {
    expect(coerceBooleanProperty({})).toBe(true);
  });

  it('should coerce an array to true', () => {
    expect(coerceBooleanProperty([])).toBe(true);
  });
});

-4

Lo scrivo sempre così:

var foo:string;

if(!foo){
   foo="something";    
}

Funzionerà bene e penso che sia molto leggibile.


21
Non funzionerebbe con i numeri perché 0supera anche il !footest.
hasen

10
Non funziona neanche per i booleani, dove undefinedè diverso da false. Questo è molto comune con i parametri opzionali della funzione booleana, in cui è necessario utilizzare l'approccio JavaScript comune:function fn(flag?: boolean) { if (typeof flag === "undefined") flag = true; /* set default value */ }
Gingi,

Sembra funzionare bene per booleani: var isTrue; if(isTrue)//skips, if(!isTrue)// enters if(isTrue === undefined)//enters. L'ho provato anche in dattiloscritto con var isTrue:booleancui non era definito, e lo stesso se si verifica. @Gingi, c'è qualcosa di diverso in quello che hai provato e in quello che ho provato?
Drenai,
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.