Làm cách nào để loại bỏ lỗi lỗi TS2533: Đối tượng có thể là 'null' hoặc 'không xác định'.


225

Tôi có một type:

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

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

  maxVisibleListItems?: number
}

Tôi khai báo một biến mô-đun toàn cầu:

var $protected : tSelectProtected = {};

Tôi đang gán giá trị phù hợp trong function1()phạm vi:

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

Sau này trong function2()phạm vi, tôi đang gọi:

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

Tôi đang gặp lỗi TypeScript:

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

Tôi biết rằng tôi có thể kiểm tra rõ ràng bằng cách sử dụng if ($protected.listEle) {$protected.listEle}để làm dịu trình biên dịch nhưng điều này dường như rất khó xử đối với hầu hết các trường hợp không tầm thường.

Làm thế nào tình huống này có thể hoặc nên được xử lý mà không vô hiệu hóa kiểm tra trình biên dịch TS?

Câu trả lời:


99

Tính năng này được gọi là "kiểm tra null nghiêm ngặt", để tắt nó để đảm bảo rằng --strictNullCheckscờ trình biên dịch không được đặt.

Tuy nhiên, sự tồn tại của nullđã được mô tảSai lầm tỷ đô , vì vậy thật thú vị khi thấy các ngôn ngữ như TypeScript giới thiệu bản sửa lỗi. Tôi thực sự khuyên bạn nên giữ nó bật.

Một cách để khắc phục điều này là đảm bảo rằng các giá trị không bao giờ nullhoặc undefined, ví dụ bằng cách khởi tạo chúng trước:

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

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

Tuy nhiên, hãy xem câu trả lời của Ryan Cavanaugh cho một lựa chọn thay thế!


8
Cá nhân tôi sử dụng nulls trong "vanilla" JavaScript để khởi tạo các biến hoặc giá trị thuộc tính. Điều này cho tôi câu trả lời thẳng nếu tồn tại var hoặc prop nhưng nó "chưa có giá trị sử dụng được" hoặc "giá trị đã bị xóa tại một số điểm thực hiện". Đó chỉ là theo quy ước. Đây có thể không phải là cách tiếp cận tốt nhất trong TypeScript như tôi có thể thấy bằng các câu trả lời ở đây. Cảm ơn bạn đã suy nghĩ của bạn.
grasnal

25
Ngay cả việc khởi tạo cũng không triệt tiêu "Đối tượng có thể là 'không xác định'" đối với tôi trong TS 2.7.2
Tyguy7

1
Có, nhưng các định nghĩa này thay đổi giá trị của các đối tượng, ví dụ, HTMLDivEuity không có mục tiêu và các sự kiện và thành phần cơ bản khác.
Clarence

5
Điều gì xảy ra nếu bạn đang cố gắng mô tả trạng thái của một số thuộc tính Đối tượng Javascript, trong đó biểu diễn thực sự của trạng thái bắt đầu là nullgì?
Timur Mamedov

1
Thêm vào đó là có một !nhà điều hành có sẵn, rất giống với các nhà điều hành trong Kotlin cho phép bạn thực hiện các kiểm tra này ngắn gọn hơn nhiều
Alvaro

598

Nếu bạn biết từ bên ngoài có nghĩa là một biểu thức không nullhoặc undefined, bạn có thể sử dụng toán tử xác nhận không null !để ép buộc các kiểu đó:

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

12
Cảm ơn đã cho tôi biết về ! - Non-null assertion operatornhà điều hành. Có vẻ như điều này chưa được ghi chép rõ ràng ( https://github.com/Microsoft/TypeScript/issues/11494 ) vì vậy bất cứ ai đang tìm câu trả lời đều đọc http://stackoverflow.com/questions/38874928/operator-in-typescript -Sau khi đối tượng-phương thức
grasnal

9
điều này cũng không có tác dụng đối với tôi trên tsc v2.7.2
Tyguy7

6
@ThomasSauvajon !toán tử ở đây không làm điều tương tự như ?trong C # nào! Nó chỉ là một xác nhận hệ thống loại ; nó sẽ không khiến chương trình của bạn không bị sập khi cố đọc thuộc tính từ nullhoặc undefined.
Ryan Cavanaugh

2
Từ sổ tay, được thêm vào tại prodding của Ryan: Cú pháp là postfix !: identifier!remove nullundefinedtừ loạiidentifier Đây là những gì Ryan đã nói, nhưng tôi cũng thấy cách này hữu ích.
John Hatton

5
Điều này không hoạt động trong Bản đánh máy 3.2.2. Nó đã được gỡ bỏ?
Lars Nyström

25

Tôi đã sử dụng:

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

Ngoài ra, bạn có thể sử dụng kiểu ép buộc:

const objectX = object as string

Mặc dù, trước khi chọn một trong các cách giải quyết trên, vui lòng xem xét kiến ​​trúc bạn đang hướng tới và nó có tác động đến bức tranh lớn hơn.


57
vì một số lý do, TSC của tôi bỏ qua điều đó nếu tuyên bố, vẫn coi đó có thể là không xác định ...
Tyguy7

9
lỗi của tôi KHÔNG được nén khi tôi sử dụngif(object!==undefined) object.function();
Jérémy

Người ta cũng có thể sử dụng so sánh kép với nullundefined, và đó không phải là một thực tiễn xấu (chỉ khi sử dụng với hai loại đó) - sự kiện TSLint sẽ cho phép bạn thực hiện. Nó dễ dàng kiểm tra nếu một cái gì đó được xác định bởi vì thay vì viết, null !== someObject && undefined !== someObjectbạn chỉ có thể sử dụngnull != someObject
Marecky

14

Không phải là câu trả lời trực tiếp cho câu hỏi của OP, nhưng trong trường hợp của tôi, tôi đã có thiết lập sau -

Bản đánh máy - v3.6.2
tslint -v5.20.0

Và sử dụng mã sau đây

const refToElement = useRef(null);

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

Tôi tiếp tục bằng cách triệt tiêu trình biên dịch cho dòng đó. Lưu ý rằng vì đó là lỗi trình biên dịch chứ không phải lỗi kẻ nói dối, // tslint:disable-next-lineđã không hoạt động. Ngoài ra, theo tài liệu, điều này hiếm khi được sử dụng, chỉ khi cần thiết -

const refToElement = useRef(null);

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

CẬP NHẬT :

Với Bản mô tả 3.7, bạn có thể sử dụng chuỗi tùy chọn , để giải quyết vấn đề trên như -

refToElement?.current?.focus();

2
Giải pháp tốt hơn nhiều so với việc vô hiệu hóa strictNullChecks, nên thận trọng khi sử dụng, hầu hết thời gian bạn muốn lỗi tham chiếu null vì nó có thể gây ra đau đầu thực sự.
Andy Braham

Thuộc tính 'getBoundingClientRect' không tồn tại trên loại 'không bao giờ'.
mqliutie

Trong trường hợp của tôi, chuỗi tùy chọn này không hoạt động. const input = useRef<HTMLInputElement>(null);if (input && input.current) { input.current.value = ''; }đã thực hiện các mẹo.
Timo

13

Giải pháp này hiệu quả với tôi:

  • đi tới tsconfig.json và thêm "rictNullChecks": false

nhập mô tả hình ảnh ở đây


Cái này cũng có tác dụng với tôi. Mặc dù nó vẫn đưa ra lỗi như, ví dụ như trong các câu lệnh đăng ký, nó không nhận ra biến kết quả, bản thảo muốn nó khai báo .subscribe (result => this.result = result.json ());
Aarchie

Bạn đã thử sử dụng toán tử 'map' chưa? Google 'rxjs / bản đồ'. Tôi cơ bản làm :. Http.get (...). Map (result => result.json ()). Đăng ký (result => {làm công cụ của bạn ở đây})
Mahesh Nepal

38
không trả lời câu hỏi. OP nói rõ ràng: 'không vô hiệu hóa kiểm tra trình biên dịch TS'
pvill 24/03/18

4
Điểm nào khi sử dụng TypeScript và loại bỏ lỗi kẻ nói dối nhằm cảnh báo bạn? Tôi nghĩ rằng tùy chọn tốt hơn là bỏ giá trị mong muốn asnếu bạn chắc chắn 100%. Tôi đã nhận được trường hợp với giá trị trả về mongodb và FindOneOrUpdate và tôi đã phải chuyển nó cho Schema vì result.valuenó được khai báo là TSchema | undefinedvà tôi đã kiểm tra result.oktrước đó
Vincent

12

Nếu bạn biết loại sẽ không bao giờ nullhoặc undefined, bạn nên khai báo nó như foo: Barkhông có ?. Khai báo một loại với ? Barcú pháp có nghĩa là nó có khả năng có thể không được xác định, đó là điều bạn cần kiểm tra.

Nói cách khác, trình biên dịch đang thực hiện chính xác những gì bạn yêu cầu. Nếu bạn muốn nó là tùy chọn, bạn sẽ cần kiểm tra sau.


1
"Trình biên dịch đang thực hiện chính xác những gì bạn yêu cầu", vì vậy ý ​​tưởng của tôi là sai, cảm ơn. Tôi cần thay đổi cách tiếp cận một chút.
grasnal

Trong trường hợp của tôi, trình biên dịch đơn giản không nhận ra rằng tôi đã kiểm tra đối tượng cho null. Tôi có một getter kiểm tra null và gọi getter đó. Vì vậy, không, nó không thực hiện chính xác những gì tôi yêu cầu (điều này không có nghĩa là tôi mong đợi nó sẽ tìm ra mọi thứ).
CWagner

9

Đây không phải là vấn đề của OP, nhưng tôi đã nhận được Object is possibly 'null'thông báo tương tự khi tôi đã khai báo một tham số là loại null một cách tình cờ:

something: null;

thay vì gán cho nó giá trị null:

something: string = null;

2
Đây là câu trả lời thực tế. Thất vọng khi bạn thực hiện kiểm tra null rõ ràng thực tế và vẫn gặp Object is possibly 'null'lỗi. Câu trả lời này giải quyết được điều đó.
Ben Racicot

5

Như một tùy chọn, bạn có thể sử dụng kiểu đúc. Nếu bạn có lỗi này từ bản in, điều đó có nghĩa là một số biến có loại hoặc không được xác định:

let a: string[] | undefined;

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

Hãy chắc chắn rằng athực sự tồn tại trong mã của bạn.


3

Kể từ TypeScript 3.7 ( https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html ), giờ đây bạn có thể sử dụng ?.toán tử để không xác định khi truy cập một thuộc tính (hoặc gọi một phương thức ) trên một đối tượng null hoặc không xác định:

inputEl?.current?.focus(); // skips the call when inputEl or inputEl.current is null or undefined

Các toán tử truy cập thuộc tính tùy chọn là ?..
aventurin

2

Mẹo cho RxJS

Tôi sẽ thường có các biến thành viên loại Observable<string>và tôi sẽ không khởi tạo nó cho đến khi ngOnInit(sử dụng Angular). Trình biên dịch sau đó giả định rằng nó chưa được khởi tạo bởi vì nó không 'được gán chắc chắn trong hàm tạo' - và trình biên dịch sẽ không bao giờ hiểungOnInit .

Bạn có thể sử dụng !toán tử xác nhận trên định nghĩa để tránh lỗi:

favoriteColor!: Observable<string>;

Một quan sát chưa được khởi tạo có thể gây ra tất cả các loại đau thời gian chạy với các lỗi như 'bạn phải cung cấp một luồng nhưng bạn đã cung cấp null'. Các !là tốt nếu bạn chắc chắn biết nó sẽ được đặt trong một cái gì đó nhưngOnInit , nhưng có thể có trường hợp giá trị được đặt trong một số cách khác ít xác định.

Vì vậy, một sự thay thế đôi khi tôi sẽ sử dụng là:

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

Nơi uninitializedđược định nghĩa toàn cầu ở đâu đó như:

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

Sau đó, nếu bạn từng sử dụng luồng này mà không được xác định, nó sẽ ngay lập tức xuất hiện lỗi thời gian chạy.


Tôi không khuyên bạn nên làm điều này ở mọi nơi, nhưng đôi khi tôi sẽ làm điều này - đặc biệt nếu dựa vào các tham số @Input được đặt từ bên ngoài
Simon_Weaver

2

Trong ReactJS, tôi kiểm tra hàm tạo nếu các biến là null, nếu chúng là tôi coi nó như một ngoại lệ và quản lý ngoại lệ một cách thích hợp. Nếu các biến không phải là null, mã sẽ tiếp tục và trình biên dịch sẽ không phàn nàn nữa sau thời điểm đó:

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

Tôi đã chạy đến đây với React khi cài đặt trạng thái và sử dụng map.

Trong trường hợp này, tôi đã thực hiện một cuộc gọi tìm nạp API và giá trị của phản hồi không được biết, nhưng nên có giá trị "Trả lời". Tôi đã sử dụng một loại tùy chỉnh cho điều này, nhưng vì giá trị có thể null, dù sao tôi cũng gặp lỗi TS. Cho phép loại nullkhông được sửa chữa nó; Ngoài ra, bạn có thể sử dụng một default parameter value, nhưng điều này là lộn xộn cho trường hợp của tôi.

Tôi đã khắc phục nó bằng cách cung cấp một giá trị mặc định trong trường hợp phản hồi trống bằng cách chỉ sử dụng toán tử ternary:

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

0

Trong bản thảo, bạn có thể làm như sau để loại bỏ error:

let subString?: string;

subString > !null; - Lưu ý dấu chấm than được thêm vào trước null.


0

Hãy thử gọi đối tượng như thế này:

(<any>Object).dosomething

Lỗi này đã xảy ra bởi vì bạn đã khai báo chúng là tùy chọn sử dụng ?. Bây giờ Typecript kiểm tra nghiêm ngặt và nó sẽ không cho phép làm bất cứ điều gì có thể undefined. Do đó, bạn có thể sử dụng (<any>yourObject)ở đây.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.