Artigo original: JavaScript TypeOf – How to Check the Type of a Variable or Object in JS

Tipos de dados e verificação de tipos são aspectos fundamentais em qualquer linguagem de programação. Muitas delas, como o Java, têm verificação de tipos estrita. Isso significa que, se uma variável é definida com um tipo específico, ela pode conter valores somente daquele tipo.

O JavaScript, entretanto, é uma linguagem fracamente (ou dinamicamente) tipada. Isso quer dizer que uma variável pode conter valores de qualquer tipo. O código em JavaScript pode ser executado assim:

let one = 1;
one = 'um';
one = true;
one = Boolean(true);
one = String('É possível');

Com isso em mente, é fundamental conhecer o tipo da variável em qualquer momento dado.

O tipo de uma variável é determinado pelo tipo do valor atribuído a ela. O JavaScript tem um operador especial, chamado typeof, que permite que você obtenha o tipo de qualquer valor.

Neste artigo, aprenderemos sobre como typeof é utilizado, juntamente com alguns cuidados que você deve ter.

Tipos de dados em JavaScript

Vamos dar uma olhada rápida nos tipos de dados em JavaScript antes de entrarmos mais a fundo no operador typeof.

Em JavaScript, existem sete tipos primitivos. Um tipo primitivo é qualquer coisa que não seja um objeto. Esses tipos em JavaScript são:

  1. String
  2. Number (número)
  3. BigInt (número inteiro "grande")
  4. Symbol (símbolo)
  5. Boolean (booleano)
  6. undefined (variável de tipo não definido - pois o valor ainda não foi definido)
  7. null (tipo nulo)

Todo o resto são objetos (em inglês, object) – incluindo array e function. Um objeto é uma coleção de pares chave-valor.

O operador typeof em JavaScript

O operador typeof recebe apenas um operando (é um operador unário). Ele avalia o tipo do operando e retorna o resultado como uma string. É assim que utilizamos o operador ao avaliar o tipo de um número, como, por exemplo, 007.

typeof 007;  // retorna 'number' - um número

Há uma sintaxe alternativa para o operador typeof, onde você pode usá-lo como uma function:

typeof(operando)

Essa sintaxe é útil quando você deseja avaliar uma expressão em vez de um valor único. Aqui temos um exemplo:

typeof(typeof 007); // retorna 'string'

No exemplo acima, a expressão typeof 007 é avaliada com o tipo number e retorna a string 'number'. typeof('number'), portanto, é o que resulta em uma 'string'.

Vamos ver outro exemplo para entender a importância dos parênteses com o operador typeof.

typeof(999-3223); // retorna "number"

Se você omitir os parênteses, no entanto, ele retornará, NaN (Not a Number – em português, "não é um número"):

typeof 999-3223; // retorna NaN

Isso ocorre porque, primeiramente, typeof 999 resultará na string "number". A expressão "number" - 32223 resultará em NaN, que é o que acontece quando você realiza uma operação de subtração entre uma string e um número.

Exemplos de uso de typeof em JavaScript

O trecho de código abaixo mostra o resultado da verificação de tipo para vários valores usando o operador typeof.

typeof 0;  //'number'
typeof +0;  //'number'
typeof -0;  //'number'
typeof Math.sqrt(2);  //'number'
typeof Infinity;  //'number'
typeof NaN;  //'number', mesmo que seja Not a Number
typeof Number('100');  //'number', depois da coerção de sucesso para número
typeof Number('freeCodeCamp');  //'number', apesar do fato de não poder fazer a coerção da string para um número
typeof true;  //'boolean'
typeof false;  //'boolean'
typeof Boolean(0);  //'boolean'
typeof 12n;  //'bigint'
typeof '';  //'string'
typeof 'freeCodeCamp';  //'string'
typeof `freeCodeCamp is awesome`;  //'string'
typeof '100';  //'string'
typeof String(100); //'string'
typeof Symbol();  //'symbol'
typeof Symbol('freeCodeCamp');  //'symbol'
typeof {blog: 'freeCodeCamp', author: 'Tapas A'};  //'object';
typeof ['This', 'is', 101]; //'object'
typeof new Date();  //'object'
typeof Array(4);  //'object'
typeof new Boolean(true);  //'object'; 
typeof new Number(101);  //'object'; 
typeof new String('freeCodeCamp');  //'object';
typeof new Object;  //'object'
typeof alert;  //'function'
typeof function () {}; //'function'
typeof (() => {});  //'function' – é uma arrow function. Assim, é necessário o parênteses
typeof Math.sqrt;  //'function'
let a;
typeof a;  //'undefined'
typeof b;  //'undefined'
typeof undefined;  //'undefined'
typeof null;  //'object'

A tabela abaixo mostra os valores de retorno da verificação de tipo com typeof:

TIPOVALOR DE RETORNO DE TYPEOF
String'string'
Number'number'
BigInt'bigint'
Symbol'symbol'
Boolean'boolean'
undefined'undefined'
Objeto function'function'
null'object'(ver abaixo!)
Qualquer outro objeto'object'

Questões importantes com typeof

Há casos em que o operador typeof pode não retornar os tipos que se espera. Isso pode causar confusão e erros. Abaixo, veremos alguns desses casos:

O tipo de NaN é number

typeof NaN;  //'number', mesmo que ele seja Not a Number (não é um número)

typeof NaN retorna 'number'. Isso é estranho, já que não deveríamos detectar NaN usando typeof. Há maneiras melhores de se lidar com isso. Veremos essas maneiras em breve.

O tipo de null é object

  typeof null;  //'object'

Em JavaScript, typeof null retorna object, o que dá a impressão errada de que null é um objeto, embora ele seja um valor primitivo.

O resultado de typeof null é, na verdade, um bug na linguagem. Houve uma tentativa de consertá-lo no passado, mas foi rejeitada devido a um problema de compatibilidade com versões anteriores.

O tipo de uma variável não declarada é undefined

Antes da ES6, uma verificação de tipo de uma variável não declarada costumava resultar em 'undefined'. Esse, no entanto, não é um modo à prova de erros de se lidar com isso.

Com a chegada da ES6, podemos declarar variáveis com escopo de bloco com as palavras-chave let ou const. Se você as utilizar com o operador typeof antes de elas serem inicializadas, verá um ReferenceError (em português, "erro de referência").

 typeof cat; // ReferenceError
 let cat = 'brownie'; 

O tipo de uma função construtora é object

Todas as funções construtoras, com exceção do construtor de Function, sempre serão do tipo 'object'.

typeof new String('freeCodeCamp'); //'object'

Isso pode causar uma certa confusão, já que esperamos que elas sejam do tipo de fato (no exemplo acima, do tipo string).

O tipo de um array é object

Embora isso esteja tecnicamente correto, pode desapontar bastante. Queremos diferenciar entre arrays e objetos, mesmo quando um array, tecnicamente, seja um objeto em JavaScript.

typeof Array(4);  //'object'

Felizmente, há maneiras de se detectar um array corretamente. Veremos isso em breve.

Para além de typeofuma verificação de tipos melhor

Agora que vimos algumas das limitações do operador typeof, vejamos como consertá-las para termos uma verificação de tipos melhor.

Como detectar NaN

Em JavaScript, NaN é um valor especial. O valor NaN representa o resultado de uma expressão aritmética que não pode, de fato, ser representada. Por exemplo,

let result = 0/0;
console.log(result);  // retorna NaN

Além disso, se realizarmos qualquer operação aritmética com NaN, o resultado sempre será NaN.

console.log(NaN + 3); // retorna NaN

A verificação de tipo de NaN usando o operador typeof não ajuda muito, pois ela retorna o tipo como 'number'. O JavaScript tem uma função global chamada isNaN() para detectar se um resultado é NaN.

isNaN(0/0); // retorna true

Porém, também temos um problema aqui.

isNaN(undefined); // retorna true para 'undefined'

Na ES6, o método isNaN() é adicionado ao objeto global Number. Esse método é muito mais confiável, sendo, portanto, o preferido.

Number.isNaN(0/0); // retorna true
Number.isNaN(undefined); // retorna false

Outro aspecto interessante de NaN é o fato de ser o único valor em JavaScript que nunca é igual a qualquer outro valor, incluindo ele mesmo. Então, há uma outra maneira de detectar NaN em ambientes onde não há suporte para a ES6:

function isNaN (input) {
  return input !== input;
}

Como detectar null em JavaScript

Como vimos anteriormente, detectar null usando o operador typeof é confuso. A maneira preferida de se verificar se algo é null é usando o operador de igualdade estrita (===).

function isNull(input) {
 return input === null;
}

Certifique-se de não usar == por engano. Se usar == no lugar de ===, você poderá ter como resultado uma detecção de tipo enganadora.

Como detectar um array em JavaScript

A partir da ES6, podemos detectar um array usando o método Array.isArray.

Array.isArray([]); // retorna true
Array.isArray({}); // retorna false

Antes da ES6, poderíamos usar o operador instanceof para determinar se algo era um array:

function isArray(input) {
  return input instanceof Array;
}

Uma solução genérica para a verificação de tipos em JavaScript

Existe uma forma de criarmos uma solução genérica para a verificação de tipos. Dê uma olhada no método Object.prototype.toString. Ele é muito poderoso e extremamente útil para se escrever um método utilitário para a verificação de tipos.

Quando Object.prototype.toString é chamado usando call() ou apply(), ele retorna o tipo do objeto no formato [object Tipo Correspondente]. A parte do Tipo Correspondente no valor de retorno é o tipo verdadeiro.

Vamos ver como isso funciona com alguns exemplos:

// retorna '[object Array]'
Object.prototype.toString.call([]); 

// retorna '[object Date]'
Object.prototype.toString.call(new Date()); 

// retorna '[object String]'
Object.prototype.toString.call(new String('freeCodeCamp'));

// retorna '[object Boolean]'
Object.prototype.toString.call(new Boolean(true));

// retorna '[object Null]'
Object.prototype.toString.call(null);

Isso quer dizer que, se simplesmente pegarmos a string de retorno e removermos a parte do object, teremos o tipo de fato. Aqui, vemos uma tentativa de se fazer isso:

function conferirTipo(valor) {
  const valor_de_retorno = Object.prototype.toString.call(valor);
  // também podemos usar uma regex para isso...
  const tipo = valor_de_retorno.substring(
           valor_de_retorno.indexOf(" ") + 1, 
           valor_de_retorno.indexOf("]"));

  return tipo.toLowerCase();
}

Agora, podemos usar a função conferirTipo para detectar os tipos:

conferirTipo([]); // 'array'
conferirTipo(new Date()); // 'date'
conferirTipo(new String('freeCodeCamp')); // 'string'
conferirTipo(new Boolean(true)); // 'boolean'
conferirTipo(null); // 'null'

Em resumo

Para resumir o que aprendemos neste artigo:

  • A verificação de tipos em JavaScript não é tão estrita como em outras linguagens de programação.
  • Use o operador typeof para a detecção de tipos.
  • Existem duas sintaxes para o operador typeof: typeof e typeof(expressão).
  • O resultado de um operador typeof pode, por vezes, ser enganoso. Precisamos confiar em outros métodos disponíveis (Number.isNaN,  Array.isArray, entre outros) nesses casos.
  • Podemos usar Object.prototype.toString para criar um método de detecção de tipos genérico.

Antes de terminar...

Obrigado pela leitura até aqui! Conecte-se com o autor do texto pelo Twitter se quiser fazer comentários.

Você também pode gostar os seguintes artigos (em inglês):

Por enquanto, é só. Até o próximo artigo. Cuide-se bem e bons estudos. 😉