Jak ukryć „błąd TS2533: Obiekt jest prawdopodobnie„ zerowy ”lub„ niezdefiniowany ””?


225

Mam type:

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

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

  maxVisibleListItems?: number
}

Deklaruję globalną zmienną modułową:

var $protected : tSelectProtected = {};

Przypisuję odpowiednią wartość w function1()zakresie:

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

Później function2()wzywam:

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

Otrzymuję błąd TypeScript:

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

Wiem, że mogę wykonać jawne sprawdzenie, if ($protected.listEle) {$protected.listEle}aby uspokoić kompilator, ale wydaje się to bardzo nieprzydatne w większości nie trywialnych przypadkach.

Jak tę sytuację można lub należy rozwiązać bez wyłączania sprawdzania kompilatora TS?

Odpowiedzi:


99

Ta funkcja nazywa się „ścisłymi kontrolami zerowymi”, aby ją wyłączyć, upewnij się, że --strictNullChecksflaga kompilatora nie jest ustawiona.

Jednak istnienie nullnie zostało opisane jako The Billion Dollar Mistake , więc jest to ekscytujące, aby zobaczyć języków takich jak maszynopis wprowadzając poprawki. Zdecydowanie zalecam włączenie go.

Jednym ze sposobów rozwiązania tego jest upewnienie się, że wartości nigdy nie są nulllub undefined, na przykład, inicjowanie ich z góry:

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

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

Zobacz odpowiedź Ryana Cavanaugha na alternatywną opcję!


8
Osobiście używam nullsw JavaScript w „waniliowym” do inicjowania wartości zmiennych lub właściwości. To daje mi prostą odpowiedź, jeśli podany var lub prop istnieje, ale nie ma on jeszcze „wartości użytecznej” lub „wartość została wyczyszczona w pewnym momencie wykonania”. To tylko konwencja. To może nie być najlepsze podejście w TypeScript, co widzę w odpowiedziach tutaj. Dziękuję za twoje przemyślenia.
grasnal

25
Nawet inicjalizacja nie tłumi, że „Obiekt jest prawdopodobnie„ niezdefiniowany ”” dla mnie w TS 2.7.2
Tyguy7

1
Tak, ale te definicje zmieniają wartości obiektów, na przykład HTMLDivElement nie ma najbliższego celu ani innych podstawowych zdarzeń i właściwości elementu.
Clarence

5
Co się stanie, jeśli spróbujesz opisać stan właściwości JavaScript Object, gdzie jest prawdziwa reprezentacja stanu początkowego null?
Timur Mamedov,

1
Dodając, że dostępny jest !operator, bardzo podobny do tych w Kotlinie, który pozwala sprawić, że kontrole będą znacznie bardziej zwięzłe
Alvaro

599

Jeśli wiesz z zewnętrznych środków, że wyrażenie nie jest nulllub undefined, możesz użyć operatora asercji niepustej! aby wymusić następujące typy:

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

12
Dziękujemy za poinformowanie mnie o ! - Non-null assertion operatoroperatorze. Wygląda na to, że sprawa nie jest jeszcze dobrze udokumentowana ( https://github.com/Microsoft/TypeScript/issues/11494 ), więc każdy, kto szuka odpowiedzi, przeczytaj ten http://stackoverflow.com/questions/38874928/operator-in-typescript -after-object-method
grasnal

9
nie ma to również dla mnie żadnego wpływu na tsc v2.7.2
Tyguy7 6.0418

6
@ThomasSauvajon !operator tutaj nie robi tego samego, co ?w języku C #! Jest to tylko stwierdzenie dotyczące systemu typów ; nie spowoduje to awarii programu podczas próby odczytu właściwości z nulllub undefined.
Ryan Cavanaugh

2
Z podręcznika dodanego u Ryana: Składnia to postfix !: identifier!usuwa nulli undefinedz rodzajuidentifier To jest to, co już powiedział Ryan, ale uważam, że ten sposób też jest pomocny.
John Hatton,

5
To nie działa w Typescript 3.2.2. Czy został usunięty?
Lars Nyström,

25

Użyłem:

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

Alternatywnie możesz użyć przymusu typu:

const objectX = object as string

Chociaż przed wybraniem jednego z powyższych obejść należy rozważyć architekturę, której szukasz, i ma to wpływ na szerszy obraz.


57
z jakiegoś powodu mój TSC ignoruje to, że jeśli oświadczenie, nadal uważa, że ​​może być niezdefiniowane ...
Tyguy7

9
mój błąd NIE jest tłumiony, gdy używamif(object!==undefined) object.function();
Jérémy

Można też użyć podwójnego porównania z nulla undefined, a to nie jest złą praktyką (tylko w przypadku korzystania z tych dwóch rodzajów) - zdarzenie TSLint pozwoli Ci to zrobić. Ułatwia sprawdzenie, czy coś jest zdefiniowane, ponieważ zamiast pisać null !== someObject && undefined !== someObjectmożna użyć po prostunull != someObject
Marecky

15

Nie jest to bezpośrednia odpowiedź na pytanie PO, ale w moim przypadku miałem następującą konfigurację -

Maszynopis - v3.6.2
tslint -v5.20.0

I używając następującego kodu

const refToElement = useRef(null);

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

Przeszedłem przez tłumienie kompilatora dla tej linii. Zauważ, że ponieważ jest to błąd kompilatora, a nie błąd linijki, // tslint:disable-next-linenie działał. Ponadto, zgodnie z dokumentacją, należy tego używać rzadko, tylko w razie potrzeby -

const refToElement = useRef(null);

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

AKTUALIZACJA :

W Typescript 3.7 możesz użyć opcjonalnego łańcucha , aby rozwiązać powyższy problem, ponieważ -

refToElement?.current?.focus();

2
O wiele lepsze rozwiązanie niż wyłączenie strictNullChecks, należy przy tym zachować ostrożność, przez większość czasu, gdy chcesz mieć zerowy błąd odniesienia, ponieważ może to powodować prawdziwe bóle głowy na drodze.
Andy Braham

Właściwość „getBoundingClientRect” nie istnieje w przypadku typu „never”.
mqliutie

W moim przypadku ten opcjonalny łańcuch nie działał. const input = useRef<HTMLInputElement>(null);i if (input && input.current) { input.current.value = ''; }załatwił sprawę.
Timo

13

To rozwiązanie działało dla mnie:

  • przejdź do tsconfig.json i dodaj „strictNullChecks”: false

wprowadź opis zdjęcia tutaj


To również działało dla mnie. Mimo że nadal podaje błąd, na przykład w instrukcjach subscribe, nie rozpoznaje zmiennej wynikowej, maszynopis chce, aby zadeklarował .subscribe (result => this.result = result.json ());
Aarchie

Czy próbowałeś już użyć operatora „mapy”? Google „rxjs / map”. Zasadniczo robię: Http.get (...). Map (result => result.json ()). Subscribe (result => {zrób tu swoje rzeczy})
Mahesh Nepal

38
nie odpowiada na pytanie. OP wyraźnie powiedział: „bez wyłączania kontroli kompilatora TS”
pvill

4
Jaki sens ma używanie TypeScript i usuwanie błędu linijek, aby cię ostrzec? Myślę, że lepszą opcją jest użycie pożądanej wartości, asjeśli masz 100% pewności. Dostałem sprawę z wartością zwracaną przez mongodb i FindOneOrUpdate i musiałem przesłać ją do schematu, ponieważ result.valuejest ona zadeklarowana jako TSchema | undefinedi już sprawdziłem result.okprzedtem
Vincent

12

Jeśli wiesz, że typ nigdy nie będzie nulllub undefined, powinieneś zadeklarować go jako foo: Barbez ?. Zadeklarowanie typu za pomocą ? Barskładni oznacza, że ​​może on być potencjalnie niezdefiniowany, co należy sprawdzić.

Innymi słowy, kompilator robi dokładnie to, o co go prosisz. Jeśli chcesz, aby była opcjonalna, musisz sprawdzić później.


1
„kompilator robi dokładnie to, o co go prosisz”, więc mój pomysł jest błędny, dzięki. Muszę trochę zmienić podejście.
grasnal

W moim przypadku kompilator po prostu nie zdawał sobie sprawy, że sprawdziłem już obiekt pod kątem wartości null. Mam moduł pobierający, który sprawdza wartość zerową i wywołuję ten moduł pobierający. Więc nie, nie robi dokładnie tego, o co prosiłem (to nie znaczy, że oczekuję, że wszystko się rozwiąże).
CWagner

9

To nie jest problem PO, ale dostałem ten sam Object is possibly 'null'komunikat, gdy przez przypadek zadeklarowałem parametr jako typ zerowy:

something: null;

zamiast przypisywać mu wartość null:

something: string = null;

2
To jest właściwa odpowiedź. Frustrujące, gdy wykonujesz rzeczywistą jawną kontrolę zerową i nadal pojawia się Object is possibly 'null'błąd. Ta odpowiedź rozwiązuje ten problem.
Ben Racicot

5

Opcjonalnie możesz użyć rzutowania typu. Jeśli występuje ten błąd z maszynopisu, oznacza to, że jakaś zmienna ma typ lub jest niezdefiniowana:

let a: string[] | undefined;

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

Upewnij się, że anaprawdę istnieją w twoim kodzie.



2

Wskazówka dla RxJS

Często będę mieć zmienne składowe typu Observable<string>i nie będę inicjalizował tego dopóki ngOnInit(używając Angulara). Kompilator następnie zakłada, że ​​jest niezainicjowany, ponieważ nie jest „definitywnie przypisany w konstruktorze” - i kompilator nigdy nie zrozumie ngOnInit.

Możesz użyć !operatora asercji w definicji, aby uniknąć błędu:

favoriteColor!: Observable<string>;

Niezainicjowana obserwowalna może powodować wszelkiego rodzaju bóle w środowisku wykonawczym z błędami takimi jak „musisz podać strumień, ale podałeś zero”. Jest !to w porządku, jeśli na pewno wiesz, że zostanie ustawione w podobny sposób ngOnInit, ale mogą zdarzyć się przypadki, w których wartość zostanie ustawiona w inny mniej deterministyczny sposób.

Alternatywą, której czasami używam, jest:

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

Gdzie uninitializedjest gdzieś zdefiniowane globalnie jako:

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

Jeśli kiedykolwiek użyjesz tego strumienia bez jego zdefiniowania, natychmiast wyrzuci on błąd czasu wykonywania.


Nie polecam robić tego wszędzie, ale czasami to robię - zwłaszcza jeśli polegam na parametrach @Input ustawionych z zewnątrz
Simon_Weaver

2

W ReactJS sprawdzam w konstruktorze, czy zmienne są puste, jeśli tak, traktuję to jak wyjątek i odpowiednio zarządzam wyjątkiem. Jeśli zmienne nie mają wartości NULL, kod jest kontynuowany, a po tym momencie kompilator nie narzeka:

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

Natknąłem się na to z React podczas ustawiania stanu i używania map.

W tym przypadku wykonałem wywołanie API i wartość odpowiedzi nie była znana, ale powinna mieć wartość „Odpowiedź”. Użyłem do tego niestandardowego typu, ale ponieważ wartość może być null, i tak dostałem błąd TS. Dopuszczenie typu nullnie rozwiązuje go; alternatywnie możesz użyć default parameter value, ale to było bałagan w moim przypadku.

Pokonałem go, podając wartość domyślną w przypadku, gdy odpowiedź była pusta, po prostu za pomocą operatora trójskładnikowego:

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

0

W maszynopisie możesz wykonać następujące czynności, aby ukryć error:

let subString?: string;

subString > !null; - Zwróć uwagę na dodany wykrzyknik przed wartością zerową.


0

Spróbuj wywołać obiekt w ten sposób:

(<any>Object).dosomething

Ten błąd nadszedł, ponieważ zadeklarowałeś je jako opcjonalne za pomocą ?. Teraz Maszynopis sprawdza dokładnie i nie pozwoli na nic, co może być undefined. Dlatego możesz użyć (<any>yourObject)tutaj.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.