Czy istnieje sposób sprawdzenia zarówno wartości „null”, jak i „undefined”?

381

Ponieważ TypeScript jest silnie napisany, po prostu używa się go if () {}do sprawdzenia nulli undefinednie brzmi dobrze.

Czy TypeScript ma do tego celu jakąś dedykowaną funkcję lub cukier składniowy?

David Liu
źródło
9
Since TypeScript is strongly-typedNie znalazłem tego w dokumentach i mam co do tego wątpliwości ...
pawciobiel,
3
Polecam poczytać o najnowszych typach nie dopuszczających wartości zerowych, jest to Typescript 2, ale już w wersji beta od dziś. [Typy niezerowalne # 7140] ( github.com/Microsoft/TypeScript/pull/7140 )
RyBolt
2
TypeScript nie ma dedykowanych funkcji do robienia czegokolwiek. To system pisania i transpiler, a nie biblioteka.

Odpowiedzi:

378

Za pomocą testu żonglowania możesz przetestować jedno nulli undefinedjedno trafienie:

if (x == null) {

Jeśli zastosujesz ścisłe sprawdzenie, będzie to prawdą tylko dla wartości ustawionych na nulli nie będzie oceniane jako prawda dla niezdefiniowanych zmiennych:

if (x === null) {

Możesz spróbować z różnymi wartościami, korzystając z tego przykładu:

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');

Wynik

„a == null”

„a jest niezdefiniowany”

„b == null”

„b === null”

Fenton
źródło
52
Co to jest „żonglerka”?
kolobok
18
@akapelko jest tam, gdzie typ jest żonglowany (tj. „czy możemy uczynić ten typ boolowskim”). Na przykład pusty ciąg znaków jest traktowany jako boolean false. Częstym błędem podczas żonglowania jest: "false" == falseniepusty łańcuch taki jak „fałsz” ocenia na true.
Fenton
12
Wynika to z „przymusu” JS.
Astravagrant
Za wyjątkiem tego, że x wynosi 0 (i to jest prawidłowa wartość), przejdzie twój niezdefiniowany / zerowy test.
Jon Gunter
3
@JonGunter byłoby to prawdą w przypadku sprawdzeń if(x)typu prawda / falsey , ale nie if(x == null), które tylko łapią nulli undefined. Sprawdź, czy var c: number = 0; check(c, 'b');nie jest to „nully” null, lub undefined.
Fenton,
268
if( value ) {
}

oceni, trueczy valuenie jest:

  • null
  • undefined
  • NaN
  • pusta struna ''
  • 0
  • false

maszynopis zawiera reguły javascript.

Ramazan Sağır
źródło
12
Co jeśli wartość jest typu logicznego?
ianstigator,
czy możesz połączyć dwie zmienne np. if (wartość1 i& wartość2), aby sprawdzić, czy oba są niezdefiniowane?
ARK
8
@ RamazanSağır tak, wiem, że wiem, ale faktem jest, że wartość 0 jest czymś ważnym, co mogę mieć, jedyne sprawdzenie, które chcę zrobić, to to, że zmienna nie jest ani zerowa, ani niezdefiniowana. Przeczytałem, że mogę to zrobić, używając val! = Null (!! = Zamiast! == sprawdza również niezdefiniowaną wartość)
Alex
4
To rozwiązanie nie będzie działać, jeśli włączona jest reguła tslint - „strict-boolean-expressions”.
ip_x
1
Będzie oceniać fałsz, jeśli ceni nas fałsz, tak proste jak to.
Ayfri
50

Czy TypeScript ma do tego dedykowaną funkcję lub cukier składniowy

TypeScript w pełni rozumie aktualną wersję JavaScript something == null.

TypeScript poprawnie wykluczy oba nulli undefinedprzy takich kontrolach.

Więcej

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

basarat
źródło
1
Lubię robić dwa równe myVar == null. Po prostu inna opcja.
David Sherret
30
== nullto właściwy sposób testowania na wartość NULL i niezdefiniowany. !!somethingjest bezużytecznym przymusem warunkowym w JS (wystarczy użyć something). !!somethingspowoduje również wymuszenie 0 i „” na false, co nie jest tym, co chcesz zrobić, jeśli szukasz wartości null / undefined.
C Snover,
39

Zrobiłem różne testy na placu zabaw maszynopisu:

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);

daje:

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

więc:

  • sprawdzanie, czy (a == null) ma prawo wiedzieć, czy a jest zerowe czy niezdefiniowane
  • sprawdzanie, czy (a! = null) ma prawo wiedzieć, czy a jest zdefiniowane
  • sprawdzanie, czy (a) jest błędne, aby wiedzieć, czy a jest zdefiniowane
Juangui Jordán
źródło
1
Dlaczego miałbyś do tego używać placu zabaw TypeScript? Nic tutaj nie ma nic wspólnego z TypeScript.
10
Ponieważ pytanie dotyczyło maszynopisu, próbowałem przetestować różne proponowane rozwiązania w stosunku do transpilatora maszynopisu.
Juangui Jordán,
6
Transpiler TS w ogóle nie przekształciłby żadnego z tych kodów.
31

Myślę, że ta odpowiedź wymaga aktualizacji, sprawdź historię edycji starej odpowiedzi.

Zasadniczo masz trzy różne przypadki: zerowy, niezdefiniowany i niezadeklarowany, zobacz poniższy fragment.

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

Pojawi się błąd mówiący, że zmienna messagejest niezdefiniowana (inaczej niezadeklarowana), oczywiście, kompilator Typescript nie powinien na to pozwolić, ale NAPRAWDĘ nic nie może temu zapobiec.

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

Kompilator chętnie po prostu skompiluje powyższy kod. Jeśli więc masz pewność, że wszystkie zmienne są zadeklarowane, możesz to po prostu zrobić

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

powyższy kod sprawdzi, nullczy undefined, ALE jeśli messagezmienna może być niezadeklarowana (dla bezpieczeństwa), możesz rozważyć następujący kod

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

Uwaga: kolejność tutaj typeof(message) !== 'undefined' && message !== nulljest bardzo ważna, musisz najpierw sprawdzić undefinedstan, w przeciwnym razie będzie ona taka sama, jak message != nulldzięki, @Jaider.

Ahmed Kamal
źródło
4
M. Kamal, jeśli coś = 0, twoja weryfikacja za pomocą! Coś sprawi ci problemy.
prostu koduj
1
@ arturios, czy możesz podać mi przykład !!
Ahmed Kamal
2
@arturios Ale 0 jest już wartością falsy w JavaScript !! o co tu chodzi?
Ahmed Kamal
1
@ Al-un nope, zobacz to w akcji tutaj
Ahmed Kamal
1
zaktualizowana wersja jest nieprawidłowa. Pierwszą rzeczą, którą należy sprawdzić, jest niezdefiniowana ... jak:if(typeof something !== 'undefined' && something !== null){...}
Jaider
27

W TypeScript 3.7 mamy teraz Opcjonalne łączenie w łańcuchy i Nullish Coalescing, aby sprawdzać null i niezdefiniowane w tym samym czasie, przykład:

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

kod ten sprawdzi, czy zdefiniowano foo, w przeciwnym razie zwróci niezdefiniowany

stary sposób :

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

to:

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

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

Z opcjonalnym łańcuchem będzie:

let x = foo?.bar();

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

kolejną nową funkcją jest Nullish Coalescing , przykład:

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

stara droga:

let x = (foo !== null && foo !== undefined) ?
foo :
bar();
Fateh Mohamed
źródło
3
To powinna być teraz akceptowana odpowiedź. Typescript 3.7 obsługuje również „Nullish Coalescing”. var foo = możliwyNieokreślonyOrNull ?? fallbackValueIfFirstValueIsUndefinedOrNull; Oto dokumentacja: typescriptlang.org/docs/handbook/release-notes/...
tkd_aj
23

Możesz spróbować

if(!!someValue)

z !!.

Wyjaśnienie

Pierwszy !zamieni twoje wyrażenie w booleanwartość.

To !someValuejest, truejeśli someValuejest fałszem i falsejeśli someValuejest prawdą . To może być mylące.

Dodając kolejne !, wyrażenie brzmi teraz, truejeśli someValuejest prawdą, a falsejeśli someValuejest fałszem , co jest o wiele łatwiejsze do opanowania.

Dyskusja

Dlaczego mam się tym przejmować, if (!!someValue)gdy coś takiego if (someValue)dałoby mi taki sam wynik?

Ponieważ !!someValuejest to właśnie wyrażenie logiczne, podczas gdy someValuemoże być absolutnie wszystkim. Ten rodzaj wyrażenia pozwoli teraz na pisanie funkcji (i Boże, potrzebujemy ich), takich jak:

isSomeValueDefined(): boolean {
  return !!someValue
}

zamiast:

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

Mam nadzieję, że to pomoże.

avi.elkharrat
źródło
więc jeśli someValue ma wartość „false” (z typem ciągu), to !! someValue ma wartość false (typ boolowski)?
Paul Cheung
Sądzę, że możesz tak powiedzieć. Ta technika jest dokładnie stosowana, aby uniknąć tego rodzaju zamieszania. Mam nadzieję, że to lubisz!
avi.elkharrat
ale to, co mnie zdezorientowało, to: „fałsz” oznacza prawdę. Właśnie z tego powodu nie mogę korzystać z tej techniki.
Paul Cheung
!!'false'jest w true'false'
toku,
więc ta technika nie może obejmować tego przypadku lub czy istnieje rozwiązanie tego problemu?
Paul Cheung
16

Bo Typescript 2.x.xpowinieneś to zrobić w następujący sposób (używając ochrony typu ):

tl; dr

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

Dlaczego?

W ten sposób isDefined()uszanuje typ zmiennej i poniższy kod będzie wiedział, że weźmie to pod uwagę.

Przykład 1 - kontrola podstawowa:

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
  }
}

Przykład 2 - typy uwzględniają:

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
  }
}
Siergiej Panfilow
źródło
14
if(data){}

to wredne! dane

  • zero
  • nieokreślony
  • fałszywe
artemitSoft
źródło
2
A jeśli dane są typu logicznego?
ianstigator,
czy możesz połączyć dwie zmienne np. if (wartość1 i& wartość2), aby sprawdzić, czy oba są niezdefiniowane?
ARK
@ianstigator Wartość logiczną można ocenić jako truelub falsetylko. Jeśli masz wartość logiczną z nullprzypisaniem lub undefinedwartością, w obu przypadkach wartość zostanie oszacowana jako false.
KBeDev
5

Jeśli używasz TypeScript, lepiej jest pozwolić kompilatorowi sprawdzać null i niezdefiniowane (lub ich możliwości), zamiast sprawdzać je w czasie wykonywania. (Jeśli chcesz sprawdzić w czasie wykonywania, to jak wiele odpowiedzi wskazuje, po prostu użyj value == null).

Użyj opcji kompilacji, strictNullChecksaby poinformować kompilator o zadławieniu możliwych wartości zerowych lub niezdefiniowanych. Jeśli ustawisz tę opcję, a to nie jest sytuacja, w której ty nie chcesz, aby wartości null i undefined, można zdefiniować typem Type | null | undefined.


źródło
5

Jeśli chcesz przekazać tslintbez ustawiania strict-boolean-expressionsna allow-null-unionlub allow-undefined-union, trzeba użyć isNullOrUndefinedz node„s utilmodułu lub toczyć własną rękę:

// 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

Niezupełnie cukier składniowy, ale przydatny, gdy twoje reguły tslint są surowe.

Graeme Wicksted
źródło
1

Szybszym i krótszym oznaczeniem nullczeków może być:

value == null ? "UNDEFINED" : value

Ta linia odpowiada:

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

Zwłaszcza, gdy masz dużo nullczeków, jest to miły krótki zapis.

Arkusz stylów Harry'ego
źródło
1

Miałem ten problem i niektóre odpowiedzi działają w porządku, JSale nie TSdlatego, że to jest powód.

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

To wszystko dobrze, ponieważ JS nie ma typów

//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);
}

W TS, jeśli zmienna nie została zdefiniowana nullprzy próbie sprawdzenia, nullczy tslint| kompilator będzie narzekał.

//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'.
T04435
źródło
1

Późno dołączyłem do tego wątku, ale uważam, że ten JavaScript jest bardzo przydatny w sprawdzaniu, czy wartość jest niezdefiniowana

 if(typeof(something) === 'undefined'){
   // Yes this is undefined
 }
Shahid Manzoor Bhat
źródło
1

Zwykle sprawdzam żonglerkę, jak to już omówił Fenton . Aby uczynić go bardziej czytelnym, możesz użyć isNil z ramdy.

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

totalAmount = isNil(totalAmount ) ? 0 : totalAmount ;
Neo
źródło
1

Mówiąc wprost, jeśli chcesz porównać TYLKO wartości puste i niezdefiniowane , użyj do tego następującego przykładowego kodu:

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}`);
}

Jeśli incomingValuenie zostanie zadeklarowane, TypeScript powinien zwrócić wyjątek. Jeśli zostanie to zadeklarowane, ale nie zdefiniowane, console.log()zwróci „Wartość przychodząca: niezdefiniowana”. Uwaga: nie używamy operatora ścisłego równości.

„Prawidłowy” sposób (sprawdź pozostałe odpowiedzi w celu uzyskania szczegółowych informacji), jeśli incomingValuenie jest booleantypem, po prostu oceń, czy jego wartość jest prawdziwa, zostanie to ocenione zgodnie z typem stałej / zmiennej. trueCiąg muszą być zdefiniowane jawnie jako ciąg pomocą = ''przyznawanie. Jeśli nie, zostanie to ocenione jako false. Sprawdźmy ten przypadek, używając tego samego kontekstu:

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"
}
KBeDev
źródło
somethingToCompare == (niezdefiniowany || null). (undefined || null) rozwiązuje na null, więc jest to luźne porównanie
czegośToCompare
@carlosvini Pewnie, celem porównania jest pełne określenie i podanie kodu w celach informacyjnych. To jest powód nieścisłego porównania równości. Odpowiedź ma być jasna i wyjaśniająca. Zmienię tekst, aby uniknąć pomyłek
KBeDev,
0

możesz użyć

if(x === undefined)
Akshay Reddy
źródło
0

Wszystko,

Odpowiedź z największą liczbą głosów, tak naprawdę nie działa, jeśli pracujesz z obiektem. W takim przypadku, jeśli właściwość nie jest obecna, sprawdzenie nie zadziała. I to był problem w naszym przypadku: zobacz tę próbkę:

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);

Wynik:

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

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

Ben Croughs
źródło
To nie jest dobry test. Żadna z tych wartości nie jest ściśle określona null . Spróbuj tego: plnkr.co/edit/NfiVnQNes1p8PvXd1fCG?p=preview
simonhamp
0

Ponieważ TypeScript jest typowanym nadzbiorem JavaScript ES6. A lodash to biblioteka javascript.

Za pomocą lodash można sprawdzić, czy wartość jest pusta czy niezdefiniowana, można to zrobić za pomocą _.isNil().

_.isNil(value)

Argumenty

wartość (*): wartość do sprawdzenia.

Zwroty

(boolean) : Zwraca true, jeśli wartość jest nullish, w przeciwnym razie false.

Przykład

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

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

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

Połączyć

Lodash Docs

7e2e63de
źródło
1
Dlaczego ta metoda to -2? Lodash nie jest dobry ze skryptem typu?
Thomas Poignant,
0

ostrożnie, jeśli używasz pamięci lokalnej, możesz skończyć z ciągiem niezdefiniowanym zamiast z niezdefiniowaną wartością:

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

Ludzie mogą uznać to za przydatne: 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);
  });
});
Robert King
źródło
-4

Zawsze piszę tak:

var foo:string;

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

To zadziała dobrze i myślę, że jest bardzo czytelne.

AlexB
źródło
21
Nie działałby dla liczb, ponieważ 0również przechodzi !footest.
hasen
10
Nie działa również w przypadku booleanów, gdzie undefinedjest inny niż false. Jest to bardzo powszechne w przypadku opcjonalnych parametrów funkcji boolowskiej, w których należy stosować wspólne podejście JavaScript:function fn(flag?: boolean) { if (typeof flag === "undefined") flag = true; /* set default value */ }
Gingi
Wydaje się OK pracy dla wartości logicznych: var isTrue; if(isTrue)//skips, if(!isTrue)// enters if(isTrue === undefined)//enters. Wypróbowałem to również w maszynopisie, z var isTrue:booleanktórym nie zdefiniowano, i to samo, jeśli sprawdza. @Gingi, czy jest coś innego w tym, co próbowałeś i co próbowałem?
Drenai,