Un objecte és un un conjunt de valors que estan relacionats i que es gestionen com un conjunt.
Objecte
Pots crear un objecte directament tal com es mostra a continuació:
const mike: any = {}
Les propietats d'un objecte de tipus any
són dinàmiques i en qualsevol moment poden canviar
En aquest cas l'objecte està buit.
Pots verificar que l'objecte no té una variable name
:
const mike = {}
console.log(mike.name) // undefined
Si vols, pots afegir una variable name
a l'objecte:
const mike: any = {}
mike.name = "Mike Smith"
console.log(mike) // { name: "Mike Smith", }
La sintaxis és la mateixa que utilitzes per definir una variable, excepte que dius que la variable name
està definida dins el context de la variable mike
.
Les variables d'un objecte és coneixen amb el nom de propietats de l'objecte, encara que a efectes pràctics no deixen se ser variables.
També pots definir les propietats de l'objecte al crear l'objecte tal com es mostra a continuació:
const mike: any = {
name: "Mike Smith",
email: "mike@gmail.com"
}
La diferència principal és que enlloc d'utilitzar =
fas servir :
.
Pots "esborrar" el contingut d'una propietat d'un objecte utilitzant null
:
const mike: any = {
name: "Mike Smith",
email: "mike@gmail.com"
}
mike.email = null
console.log(mike.age) // undefined
console.log(mike.email) // null
En qualsevol moment pots consultar les propietats d'un objecte amb la funció Object.keys()
:
const mike: any = {
name: "Mike Smith",
email: "mike@gmail.com",
}
mike.age = 45
console.log(Object.keys(mike)) // [ 'name', 'email', 'age']
Pots eliminar una propietat de l'objecte amb delete
:
const mike: any = {
name: "Mike Smith",
email: "mike@gmail.com"
}
delete mike.email
console.log(Object.keys(mike)) // [ "name" ]
En qualsevol moment pots utilitzar la funció Object.values()
per conèixer els valors de les propietats, o Object.entries()
si necessites a la vegada les claus de les propietats i el seu valor.
const mike: any = {
name: "Mike Smith",
email: "mike@gmail.com"
}
mike.phone = "+1 898 898 99"
console.log(Object.entries(mike))
El resultat és una llista de llistes:
[
[ "name", "Mike Smith" ], [ "email", "mike@gmail.com" ], [ "phone", "+1 898 898 99" ]
]
Enlloc d'utilitzar la notació .
, pots utilitzar la notació []
per treballar amb les propietats d'un objecte:
const mike: any = {
["name"]: "Mike Smith",
}
mike["phone"] = "+1 898 898 99"
console.log(mike["name"]) // Mike Smith
Això és util quan utilitzes propietats dinàmiques, o noms que no respecten la sintaxis admissible de TypeScript pels noms:
const cart: any = {}
while (true) {
const product = prompt("Product?")
if (product == null) break
cart[product] = cart[product] == undefined ? 1 : cart[product] += 1
}
console.log(cart)
> bun test.ts
Product? Pizza
Product? Pizza
Product?
{
Pizza: 2,
}
O quan vols recorrer totes les propietats d'un objecte és mitjançant un bucle for..in
:
const mike: any = {
name: "Mike Smith",
email: "mike@gmail.com"
}
mike.phone = "+1 898 898 99"
for(const key in mike){
console.log(`${key}:\t${mike[key]}`)
}
A continuació tens el resultat:
> bun test.ts
name: Mike Smith
email: mike@gmail.com
phone: +1 898 898 99
Activitat
1.- Escriu el codi, una linia per cada acció:
- Crea un objecte
user
buit. - Afegeix la propietat
name
amb el valorJohn
. - Afegeix la propietat
surname
amb el valorSmith
- Modifica el valor de
name
aPete
. - Elimina la propietat
surname
de l'objecte.
let user: any = {}
user.name = "John"
user.surname = "Smith"
user.name = "Pete"
delete user.surname
2.- Tenim un objecte que emmagatzema el salaris del nostre equip:
const salaries:any = {
John: 100,
Ann: 160,
Pete: 130
}
Escriu el codi per sumar tots els salaris i emmagatzemar el resultat a la variable result
. En aquest exemple el resultat ha de ser 390
.
Si salaries
estigues buit el resultat hauria de ser 0
.
const salaries:any = {
John: 100,
Ann: 160,
Pete: 130
}
let result = 0
for (const key in salaries) {
result += salaries[key]
}
console.log(result)
Tipus
Un tipus et permet definir les propietats que ha de tenir un objecte si o si.
Per exemple, pots definir el tipus Person
:
type Person = {
name: string,
email: string
}
Al crear una variable, pots dir a Typescript que aquella variable només pot tenir objectes de tipus Person
:
const laura: Person = {
name: "Laura",
email: "laura@gmail.com"
}
Ara TypeScript t'avisa de que hi ha coses que pots fer que no hauries de fer:
laura.age = 34 // La propietat 'age' no existeix en el tipus Person.
delete laura.name // No hauries d'eliminar la propietat 'age' d'un objecte de tipus Person
console.log(laura.age)
TypesScript només avisa: pots executar el codi sense problemes:
> bun test.ts
{
email: "laura@gmail.com",
age: 34,
}
I en aquest cas no passa res.
Però en l'exemple que es mostra a continuació si que es produeix un error:
function print(person: Person) {
console.log(person.name.toUpperCase())
}
delete laura.name // Error
print(laura)
Llavors el codi no funciona com tenia que funcionar perquè la funció print
espera un paràmetre de tipus Person
que tingui la propietat name
:
> bun test.ts
...
12 |function print(p: Person) {
13 | console.log(p.name.toUpperCase())
^
TypeError: undefined is not an object (evaluating 'p.name.toUpperCase')
at print (C:\Users\david\Workspace\yup\test.ts:13:19)
at C:\Users\david\Workspace\yup\test.ts:17:1
Duck typing 🦆
Un tipus només serveix per dir quines propietats ha de tenir un objecte, el nom del tipus és indiferent.
Un objecte és d'un tipus concret si té tots les propietats que demana aquell tipus.
Per exemple, en aquest codi els tipus Person
i Alien
són intercanviables:
type Alien = {
name: string,
email: string
}
function print(a: Alien) {
console.log(a.name)
}
const laura: Person = {
name: "Laura",
email: "laura@gmail.com"
}
print(laura)
const alienLaura: Alien = laura
En aquest cas un Alien
👽 i un Person
són iguals 👱: tenen, i només tenen, name
i email
.
Pots escriure un codi per enviar missatges a la Laura: tens el seu correu, i no té cap importància si és un alien o no.
Propietats opcionals
Pots utilitzar el símbol ?
per definir una propietat com opcional.
En aquest exemple la propietat email
és de tipus string | undefined
type Person = {
name: string,
email?: string
}
const laura: Person = {name: "Laura"}
laura.email.toUpperCase()
Si intentes utilitzar la propietat email
directament, TypeScript et diu que potser no està definida.
Primer has de verificar que està definida:
const laura: Person = {name: "Laura"}
if (laura.email != undefined){
laura.email.toUpperCase()
}
Subtipus
Al crear un objecte, el tipus de la variable ha de coincidir amb les propietats de l'objecte.
Aquest codi és erroni perquè el tipus Named
no té la propietat age
:
type Person = {
name: string,
age?: number
}
type Named = {
name: string
}
const named: Named = {name: "Laura", age: 30}
Però pots passar la referència de la variable a qualsevol altre variable que tingui un tipus que sigui subtipus del tipus.
O de manera més llana, que tingui algunes (i només algunes) de les propietats del tipus.
type Person = {
name: string,
age?: number
}
type Named = {
name: string
}
function print(named: Named) {
console.log(named.name)
}
const laura: Person = {name: "Laura", age: 30}
const _: Named = laura
print(laura)
Qualsevol objecte de tipus Person
es pots utilitzar com un objecte de tipus Named
.
Llistes
També pots restringir el tipus d'elements que pot tenir una llista:
const team: Person[] = [{
name: "Laura",
email: "laura@gmail.com"
}, {
name: "David",
email: "david@gmail.com"
}]
D'aquesta manera pots escriure codi que estas segur que funcionarà:
console.log(team.map(p => p.name)) // [ "Laura", "David" ]
Constructor
Si has de crear molts cops un objecte amb les mateixes propietats pots utilitzar una funció.
function Employee(name: string, salary: number): Employee {
return {name, salary}
}
const david = Employee("David", 10000)
console.log(david.salary) // 10000
Dins de la funció pots aplicar la lògica que vulguis 😁:
function Employee(name: string, salary: number): Employee {
if (name == "David")
salary += 30000
return {name, salary}
}
const david = Employee("David", 10000)
console.log(david.salary) // 40000
Tipus anònim
En TypeScript el nom del tipus no te gaire importància: pots declarar el tipus que ha de tenir una variable o el paràmetre d'una funció sense necessitat de posar-li nom:
const eva: { name: string, email: string } = {
name: "Eva",
email: "eva@gmail.com"
}
function sendMessage(to: { name: string, email: string }, message: string) {
console.log(`${to.email} `)
}
sendMessage(eva, "Ens veiem dissabte")
També és útil quan una funció vol tornar un objecte com resultat:
function sendMessage(to: { name: string, email: string }, message: string): { error: boolean, errorMessage?: string } {
console.log(`${to.email} `)
return {error: true, errorMessage: "Encara no està implementat"}
}
const result = sendMessage({name: "Eva", email: "eva@gmail.com"}, "Ens veiem dissabte")
if (result.error) {
console.log(result.errorMessage)
}
Funció
Una funció és un valor com qualsevol altre i pots ser la propietat d'un objecte:
const chat = {
name: "whale",
posts: [""],
post: function (message: string) {
this.posts.push(message)
console.log(message)
}
}
chat.post("Hello, World!")
chat.post("What do you think about ...")
console.log(chat.posts)
Una funció definida com a propietat t'un objecte pot accedir a les altres propietats de l'objecte amb l'expressió this
.
Naturalment també pots definir el tipus de l'objecte:
type Chat = {
name: string,
posts: string[]
post: (message: string) => void
}
const chat: Chat = {
name: "whale",
posts: [],
post: function (message: string) {
this.posts.push(message)
console.log(message)
}
}