null e undefined em TypeScript
Assim como no JavaScript, no TypeScript existem os tipos especiais undefined
e null
, que aceitam, respectivamente, os valores undefined
e null
.
O uso de undefined
e null
depende da configuração do compilador, especificamente do parâmetro strictNullChecks
. Por padrão, esse parâmetro está definido como false
, o que significa que podemos usar esses tipos como no JavaScript:
let a: undefined = undefined;
let b: null = null;
Na prática, podemos atribuir os valores undefined
e null
a variáveis de outros tipos, como number
:
let x: number = undefined;
console.log(x);
x = null;
console.log(x);
x = 5;
console.log(x);
Nesse contexto, null
e undefined
atuam como subtipos de outros tipos e são úteis em operações onde o resultado é incerto: por exemplo, quando o valor pode ser um número, uma string ou null
. Para evitar possíveis erros, podemos verificar se o valor é undefined
ou null
, da mesma forma que no JavaScript.
Contudo, a ausência de verificações desses tipos pelo compilador pode ser uma fonte de bugs. Por isso, é comum utilizar o parâmetro strictNullChecks
na compilação. Isso pode ser feito ao ativar a flag no comando de compilação:
--strictNullChecks
Ou definindo o valor true
no arquivo de configuração tsconfig.json
:
{
"compilerOptions": {
"target": "es2015",
"noImplicitAny": true,
"noEmitOnError": true,
"strictNullChecks": true,
"outFile": "app.js"
}
}
Nesse cenário, se tentarmos atribuir um valor do tipo undefined
ou null
a uma variável de outro tipo, o compilador lançará um erro. Por exemplo, ao compilar o código anterior:
let x: number = undefined;
console.log(x);
x = null;
console.log(x);
x = 5;
console.log(x);
O compilador produzirá as seguintes mensagens de erro:
app.ts:1:5 - error TS2322: Type 'undefined' is not assignable to type 'number'. let x: number = undefined; app.ts:3:1 - error TS2322: Type 'null' is not assignable to type 'number'. x = null; Found 2 errors.
Também ocorrerá um erro se tentarmos atribuir o valor undefined
a uma variável do tipo null
, ou vice-versa.
Ainda assim, existem situações em que não sabemos com certeza se uma variável, ou um parâmetro de função, contém um valor ou se ele está ausente. Isso é especialmente comum quando recebemos dados de uma fonte externa, como uma requisição a um recurso de rede. Nesses casos, pode ser necessário permitir que uma variável ou parâmetro aceite o valor null
. Para isso, podemos usar tipos de união. Exemplo:
let userId: number | null = null;
function printId(id: number | null) {
if (id === null) {
console.log("Usuário ausente");
} else {
console.log(`ID do usuário: ${id}`);
}
}
printId(userId); // Usuário ausente
userId = 45;
printId(userId); // ID do usuário: 45
Aqui, a variável userId
representa uma união entre os tipos number
e null
, permitindo que ela receba tanto um valor numérico quanto null
.
De maneira similar, a função printId
, através do parâmetro id
, pode receber tanto um valor null
quanto um número.
Operador !
O operador !
(non-null assertion operator) permite indicar que um objeto não é null
ou undefined
. Veja o exemplo abaixo:
const header: HTMLElement | null = document.getElementById("header");
header.innerText = "Hello TypeScript!";
A função embutida document.getElementById()
retorna um elemento da página da web pelo seu ID, o que pode ser do tipo HTMLElement
ou null
, caso o elemento com o ID fornecido não exista. Após obter o elemento, tentamos alterar seu conteúdo de texto usando a propriedade innerText
.
Embora o código pareça correto, com a opção strictNullChecks
ativada, o compilador lançará um erro durante a compilação:
app.ts:2:1 - error TS2531: Object is possibly 'null'. header.innerText = "Hello TypeScript!"; Found 1 error.
Para evitar o erro, usamos o operador !
:
const header: HTMLElement | null = document.getElementById("header");
header!.innerText = "Hello TypeScript!";
O operador !
é colocado após o objeto que pode teoricamente ser null
, antes de acessar suas propriedades ou métodos:
object!.property;
object!.method();
No entanto, é importante lembrar que este operador não altera o valor do objeto. Se o objeto for null
ou undefined
, o operador não irá impedir erros. O código será compilado, mas, durante a execução, o programa ainda lançará um erro.
Portanto, recomenda-se utilizar esse operador apenas quando tivermos certeza absoluta de que o objeto não é null
ou undefined
.