Objetos no TypeScript
Assim como no JavaScript, além dos tipos de dados simples, é possível criar objetos que consistem em outros objetos e dados primitivos. Por exemplo:
let person = { name: "Tom", age: 23 };
console.log(person.name);
// Alternativa para acessar a propriedade
console.log(person["name"]);
No entanto, embora este seja essencialmente o mesmo objeto que poderíamos usar em JavaScript, devido à tipagem estática do TypeScript, há algumas restrições. Por exemplo, se tivermos o seguinte código:
let person = { name: "Tom", age: 23 };
person = { name: "Bob" }; // Erro!
Na segunda linha, ocorrerá um erro, pois o compilador, depois da primeira linha, assume que o objeto person
terá duas propriedades: name
e age
, que são do tipo string
e number
, respectivamente. Assim, a variável person
é do tipo { name: string; age: number }
. Podemos especificar isso explicitamente:
let person: { name: string; age: number } = { name: "Tom", age: 23 };
console.log(person.name);
Dessa forma, podemos atribuir a essa variável outro objeto, desde que corresponda ao tipo { name: string; age: number }
, como no exemplo a seguir:
let person = { name: "Tom", age: 23 };
person = { name: "Bob", age: 35 }; // Correto
Propriedades Opcionais
No TypeScript, é possível definir propriedades opcionais. Para isso, basta adicionar o símbolo de interrogação ?
após o nome da propriedade:
let person: { name: string; age?: number }; // A propriedade age é opcional
Neste caso, a propriedade age
é opcional, então não é necessário fornecer um valor para ela:
let person: { name: string; age?: number };
person = { name: "Tom", age: 23 };
console.log(person.name); // Tom
person = { name: "Bob" }; // Correto, a propriedade age é opcional
console.log(person.name); // Bob
Ao acessar uma propriedade não definida, será retornado undefined
:
let person: { name: string; age?: number } = { name: "Tom", age: 23 };
console.log(person.age); // 23
person = { name: "Bob" };
console.log(person.age); // undefined
Por isso, ao trabalhar com propriedades opcionais, é recomendável verificar se o valor é undefined
antes de utilizá-lo:
let person: { name: string; age?: number } = { name: "Tom", age: 36 };
if (person.age !== undefined) {
console.log(person.age);
}
Objetos em Funções
Funções podem aceitar objetos como parâmetros e também podem retornar objetos. Nesses casos, é necessário especificar o tipo do objeto tanto para os parâmetros quanto para o retorno. Exemplo de um objeto como parâmetro:
function printUser(user: { name: string; age: number }) {
console.log(`name: ${user.name} age: ${user.age}`);
}
let tom = { age: 36, name: "Tom" };
printUser(tom);
Aqui, o parâmetro user
da função printUser
é do tipo { name: string; age: number }
, ou seja, um objeto com duas propriedades, name
do tipo string
e age
do tipo number
.
O objeto passado como parâmetro pode conter mais propriedades do que o esperado, desde que contenha as propriedades necessárias:
function printUser(user: { name: string; age: number }) {
console.log(`name: ${user.name} age: ${user.age}`);
}
let bob = { name: "Bob", age: 44, isMarried: true };
printUser(bob);
Aqui, a variável bob tem o tipo { name: string; age: number; isMarried: boolean }
, mas ainda assim é compatível com o tipo { name: string; age: number }
.
Objeto como Resultado de Função
Também é possível definir um objeto como o valor de retorno de uma função:
function defaultUser(): { name: string; age: number } {
return { name: "Tom", age: 37 };
}
let user = defaultUser();
console.log(`name: ${user.name} age: ${user.age}`);
Operador in
O operador in
verifica se uma determinada propriedade existe em um objeto. Ele retorna true
se a propriedade estiver presente no objeto, e false
caso contrário. Exemplo:
let tom: { name: string; age?: number } = { name: "Tom", age: 23 };
let bob: { name: string; age?: number } = { name: "Bob" };
function printUser(user: { name: string; age?: number }) {
if ("age" in user) {
console.log(`Name: ${user.name} Age: ${user.age}`);
} else {
console.log(`Name: ${user.name}`);
}
}
printUser(tom);
printUser(bob);
Neste exemplo, a função printUser()
aceita um objeto do tipo { name: string; age?: number }
, ou seja, a propriedade age
pode estar presente ou não. Usamos o operador in
para verificar se a propriedade existe:
if ("age" in user) {...}
O nome da propriedade é passado como uma string.
Desestruturação de Objetos
Se uma função recebe um objeto como parâmetro, o TypeScript permite desestruturar automaticamente suas propriedades:
function printUser({ name, age }: { name: string; age: number }) {
console.log(`name: ${name} age: ${age}`);
}
let tom = { name: "Tom", age: 36 };
printUser(tom);
Aqui, a função printUser()
desestrutura automaticamente o objeto passado como parâmetro, separando suas propriedades name
e age
em variáveis. O importante é que os nomes dessas variáveis correspondam aos nomes das propriedades do objeto.
Algumas propriedades podem ser opcionais:
function printUser({ name, age }: { name: string; age?: number }) {
if (age !== undefined) {
console.log(`name: ${name} age: ${age}`);
} else {
console.log(`name: ${name}`);
}
}
let tom = { name: "Tom" };
printUser(tom); // name: Tom
let bob = { name: "Bob", age: 44 };
printUser(bob); // name: Bob age: 44
Nesse caso, a propriedade age
é opcional, então a função pode ser chamada com ou sem essa propriedade.
Também é possível definir valores padrão para as propriedades:
function printUser({ name, age = 25 }: { name: string; age?: number }) {
console.log(`name: ${name} age: ${age}`);
}
let tom = { name: "Tom" };
printUser(tom); // name: Tom age: 25
let bob = { name: "Bob", age: 44 };
printUser(bob); // name: Bob age: 44
Neste exemplo, a propriedade age
tem um valor padrão de 25, caso não seja fornecida no objeto passado para a função.