В JavaScript (и, соответственно, TypeScript) есть два нижних типа: null и undefined. Они предназначены для обозначение разных вещей:
- Что-то еще не инициализированное:
undefined. - Что-то недоступное в данный момент:
null.
Факт в том, что вам придется столкнуться с обоими. Просто проверьте их через ==
/// Представьте, что вы делаете `foo.bar == undefined`, где bar может быть одним из:
console.log(undefined == undefined); // true
console.log(null == undefined); // true
// Вам не нужно переживать из-за ложных значений в этой проверке
console.log(0 == undefined); // false
console.log('' == undefined); // false
console.log(false == undefined); // falseПоручите == null проверить undefined или null. Как правило, нет необходимости делать между ними различия.
function foo(arg: string | null | undefined) {
if (arg != null) {
// arg должен быть строкой, поскольку `!=` исключает и null и undefined.
}
}Одно исключение: значения undefined корневого уровня, которые мы обсудим далее.
Помните как я сказал вам использовать == null? Конечно помните (ведь это было только что ^). Не используйте его для вещей корневого уровня. В строгом режиме, если вы используете foo и foo является undefined, вы получите исключение ReferenceError и весь стек вызовов прервётся.
Вы должны использовать строгий режим ... и на самом деле компилятор TS включит его для вас, если вы используете модули ... подробнее об этом будет сказано позже, так что не парьтесь :)
Поэтому чтобы проверить задана ли переменная на глобальном уровне, используйте typeof:
if (typeof someglobal !== 'undefined') {
// someglobal теперь можно безопасно использовать
console.log(someglobal);
}Потому что TypeScript дает вам возможность документировать ваши структуры отдельно от значений. Вместо того чтобы делать так:
function foo(){
// if Something
return {a:1,b:2};
// else
return {a:1,b:undefined};
}вы должны использовать аннотацию типов:
function foo():{a:number,b?:number}{
// if Something
return {a:1,b:2};
// else
return {a:1};
}Функции колбеков в стиле Node (вроде (err,somethingElse)=>{ /* что-нибудь */ }) обычно вызываются с err равным null, если нет ошибок. Как бы то ни было, в общем случае просто используйте проверку на истинность:
fs.readFile('someFile', 'utf8', (err,data) => {
if (err) {
// сделать что-нибудь
} else {
// ошибок нет
}
});Когда создаёте свои собственные API, в подобных ситуациях нормально использовать null для согласованности. Но, честно говоря, лучше посмотреть в сторону промисов, тогда вам вообще не придется париться из-за пустых значений ошибок (вы обработаете их через .then и .catch).
Для примера, ужасная функция:
function toInt(str:string) {
return str ? parseInt(str) : undefined;
}может быть написана намного лучше:
function toInt(str: string): { valid: boolean, int?: number } {
const int = parseInt(str);
if (isNaN(int)) {
return { valid: false };
}
else {
return { valid: true, int };
}
}В стандарте JSON есть поддержка кодирования null, но нет undefined. При кодировании в JSON объекта, с атрибутом равным null, атрибут будет включён с нулевым значением, в то время как атрибут со значением undefined будет полностью исключён.
JSON.stringify({willStay: null, willBeGone: undefined}); // {"willStay":null}В результате, базы данных, основанные на JSON могут поддерживать значения null, но не undefined. Поскольку атрибуты со значением null закодированы, вы можете намеренно очистить атрибут, установив его значение в null перед кодированием и передав объект в удаленное хранилище.
Установка значений undefined может сэкономить память и затраты на передачу, поскольку названия атрибутов не будут закодированы. Однако, это может усложнить семантику очистки значений по сравнению с отсутствующими значениями.
Команда TypeScript не использует null : TypeScript coding guidelines и это не вызвало никаких проблем. Дуглас Крокфорд считает, что null - это плохая идея и всем нам лучше использовать undefined.
Как бы то ни было, стиль NodeJS использует null для аргументов Error в качестве стандарта, посколько это означает Что-то в настоящий момент недоступно. Лично я не хочу разрываться между ними двумя, ведь большинство проектов используют библиотеки с разными подходами, и в обоих случаях использую просто == null.