Перейти к содержанию

strictNullChecks

По умолчанию null и undefined можно назначать всем типам в TypeScript, например:

1
2
3
let foo: number = 123;
foo = null; // Okay
foo = undefined; // Okay

Это спроектировано по образцу того, как многие люди пишут JavaScript. Однако, как и в других случаях, TypeScript позволяет вам явно указать, чему можно, а чему нельзя присвоить null или undefined.

В режиме strictNullChecks, значения null и undefined различаются:

1
2
let foo = undefined;
foo = null; // не Okay

Допустим, у нас есть интерфейс Member:

1
2
3
4
interface Member {
    name: string;
    age?: number;
}

Не каждый Участник предоставит свой возраст, поэтому возраст является необязательным свойством, то есть значение age может быть или не быть undefined.

undefined - корень всех зол. Это часто приводит к ошибкам во время выполнения. Легко написать код, который будет выдавать Error во время выполнения:

1
2
3
4
5
getMember()
  .then(member: Member => {
    const stringifyAge = member.age.toString() // Невозможно прочитать
    // свойство toString из undefined
  })

Но в режиме strictNullChecks эта ошибка будет обнаружена во время компиляции:

1
2
3
4
getMember()
  .then(member: Member => {
    const stringifyAge = member.age.toString() // Возможно, объект 'undefined'
  })

Оператор утверждения не-null

Новый постфиксный оператор ! может использоваться для утверждения, что его операнд не равен null и не-undefined в случаях, где средство проверки типов не может сделать логический вывод об этом. Например:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Скомпилировано с --strictNullChecks
function validateEntity(e?: Entity) {
    // Выбрасываем исключение, если e - null или невалидный объект
}

function processEntity(e?: Entity) {
    validateEntity(e);
    let a = e.name; // ОШИБКА TS: e может быть null.
    let b = e!.name; // OKAY. Мы утверждаем, что e не null.
}

Обратите внимание, что это просто утверждение, и, как при утверждении типа, вы сами несете ответственность за то, чтобы значение не было null. Не-null утверждение, по сути, означает, что вы говорите компилятору: "Я знаю, что оно не null, поэтому позволь мне использовать его, как если бы оно не было null".

Оператор утверждения окончательного присваивания

TypeScript также будет жаловаться на свойства в классах, которые не инициализированы, например:

1
2
3
4
5
6
7
8
9
class C {
    foo: number; // OKAY, так как назначено в конструкторе
    bar: string = 'hello'; // OKAY, так как есть инициализатор свойства
    baz: boolean; // ОШИБКА TS: свойство 'baz' не имеет инициализатора
    // и не назначается напрямую в конструкторе.
    constructor() {
        this.foo = 42;
    }
}

Вы можете использовать утверждение окончательного присваивания с постфиксом к имени свойства, чтобы сообщить TypeScript, что вы инициализируете его где-нибудь, кроме конструктора, например:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class C {
    foo!: number;
    // ^
    // Обратите внимание на этот восклицательный знак!
    // Это модификатор "утверждения окончательного присваивания".

    constructor() {
        this.initialize();
    }
    initialize() {
        this.foo = 0;
    }
}

Вы также можете использовать это утверждение с простыми объявлениями переменных, например:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
let a: number[]; // Нет утверждения
let b!: number[]; // Утвердить

initialize();

a.push(4); // TS ОШИБКА: переменная использована до присвоения
b.push(4); // OKAY: из-за утверждения

function initialize() {
    a = [0, 1, 2, 3];
    b = [0, 1, 2, 3];
}

Как и все утверждения, вы говорите компилятору доверять вам. Компилятор не будет жаловаться, даже если код на самом деле не всегда присваивает свойство.

Комментарии