JavaScript (e, por extensão, TypeScript ) tem dois tipos inferiores: null
e undefined
. Eles têm a intenção de significar coisas diferentes:
- Algo não foi inicializado:
undefined
. - Algo está indisponível no momento:
null
.
Fato é que você precisará lidar com ambos. Para esse caso usamos simplesmente o ==
para checar.
/// Imagine que você está fazendo `foo.bar == undefined` onde bar pode ser uma das seguintes:
console.log(undefined == undefined); // true
console.log(null == undefined); // true
// Você não precisa se preocupar com valores falsos efetuados por meio dessa verificação
console.log(0 == undefined); // false
console.log('' == undefined); // false
console.log(false == undefined); // false
Recomendo == null
para verificar ambos undefined
ou null
. Você geralmente não quer fazer uma distinção entre os dois.
function foo(arg: string | null | undefined) {
if (arg != null) {
// arg deve ser uma string tal como a`!=` condição exclui os dois, null e undefined.
}
}
Uma exceção, os valores indefinidos no nível raiz que discutiremos a seguir.
Lembre-se de como eu disse que você deveria usar == null
. Claro que sim (porque acabei de dizer ^ ). Não o use para coisas no nível da raiz. No modo strict, se você usa foo
e foo
como undefined, você obtém uma exceção ReferenceError
e toda a pilha de chamadas é desativada.
Você deve usar o modo strict ... e, de fato, o compilador TS o inserirá para você se você usar os módulos ... mais sobre isso mais tarde no livro, assim você não tem que ser explícito sobre isso :)
Então, para verificar se uma variável é definida ou não em um nível global você normalmente usa typeof
:
if (typeof someglobal !== 'undefined') {
// someglobal agora é seguro de usar
console.log(someglobal);
}
Como o TypeScript oferece a oportunidade de documentar suas estruturas separadamente dos valores, em vez de coisas como:
function foo(){
// Se for alguma coisa
return {a:1,b:2};
// outro caso
return {a:1,b:undefined};
}
você deve usar uma anotação de tipo:
function foo():{a:number,b?:number}{
// Se for alguma coisa
return {a:1,b:2};
// outro caso
return {a:1};
}
As funções de retorno de chamada ou callbacks no node(por exemplo, (err, somethingElse) => {/* something */}
) são geralmente chamadas com err
definido como null
se não houver um erro. Você geralmente usa uma verificação de verdade para isso de qualquer maneira:
fs.readFile('someFile', 'utf8', (err,data) => {
if (err) {
// faça alguma coisa
} else {
// sem erro
}
});
Ao criar suas próprias APIs, é normal usar null
nesse caso para obter consistência. Com toda a sinceridade para suas próprias APIs, você deve considerar suas promises; nesse caso, você realmente não precisa se preocupar com valores de erro ausentes (você os trata com .then
vs. .catch
).
Por exemplo, uma função horrível como esta:
function toInt(str:string) {
return str ? parseInt(str) : undefined;
}
pode ser muito melhor desse jeito:
function toInt(str: string): { valid: boolean, int?: number } {
const int = parseInt(str);
if (isNaN(int)) {
return { valid: false };
}
else {
return { valid: true, int };
}
}
A equipe do TypeScript não usa null
: Diretrizes de codificação do TypeScript e não causa nenhum problema. Douglas Crockford acha que null
é uma péssima idéia e todos nós devemos apenas usar undefined
.
No entanto, as bases de código no estilo NodeJS usam null
para argumentos de erro como padrão, pois denota algo está indisponível no momento
. Pessoalmente, não me importo em distinguir entre os dois, pois a maioria dos projetos usa bibliotecas com opiniões diferentes e apenas descarta os dois com == null
.