Objects and Type Annotations
Objects are a fundamental part of JavaScript and TypeScript. TypeScript allows you to add type annotations to object properties, ensuring type safety when working with objects.
Inline object types
Object types can be defined inline when declaring variables:
let pizza: { name: string; price: number } = {
name: "Margherita",
price: 10.99
};
This tells TypeScript that pizza is an object with:
- A
nameproperty of typestring - A
priceproperty of typenumber
Type safety with objects
TypeScript ensures you use the correct types. Run the code below to see errors when trying to assign incorrect value types:
Loading code...
let pizza: { name: string; price: number } = {
name: "Margherita",
price: 10.99
};
pizza.name = "Pepperoni"; // works
pizza.price = 12.99; // works
pizza.name = 42; // error
pizza.toppings = ["pepperoni"]; // error
Optional properties
Object properties can be optional by using the ? operator:
Loading code...
let pizza: { name: string; price: number; toppings?: string[] } = {
name: "Margherita",
price: 10.99
// toppings are optional, so we don't need to include it
};
// but can still add it later if needed
pizza.toppings = ["cheese", "basil"];
console.log(pizza);
Readonly properties
You can make properties read-only using the readonly keyword:
Loading code...
let pizza: { readonly name: string; price: number } = {
name: "Margherita",
price: 10.99
};
pizza.price = 12.99; // works
pizza.name = "Pepperoni"; // error: Cannot assign to 'name' because it is a read-only property
console.log(pizza.name); // works- can log/read pizza name
Nested objects
Nested objects can also have types too. This example includes a nested customer object:
Loading code...
let order: {
pizzaName: string;
customer: {
name: string;
address: string;
phone: string;
};
} = {
pizzaName: "Margherita",
customer: {
name: "Homer",
address: "123 Main St",
phone: "555-1234"
}
};
order.customer.name = 33; // error: Type 'number' is not assignable to type 'string'
order.customer.name = "Marge"; // works (string)
console.log(order);
Object methods
Methods on objects can also be typed:
let calculator: {
add: (a: number, b: number) => number;
subtract: (a: number, b: number) => number;
} = {
add: (a, b) => a + b,
subtract: (a, b) => a - b
};
Type inference with objects
TypeScript can infer object types from the initial values provided:
Loading code...
let person = {
name: "Bart",
age: 10
};
console.log(typeof(person.name));
console.log(typeof(person.age));
However, TypeScript will infer the exact shape, so you can't add new properties:
Loading code...
let person = {
name: "bart",
age: 10
};
person.email = "[email protected]"; // Error: Property 'email' does not exist
Index signatures
Index signatures can be used for objects with dynamic properties. You may not know all the properties in advance, but know the data type. This example expects a string value for the key and value:
Loading code...
let dictionary: { [key: string]: string } = {
hello: "bonjour",
goodbye: "au revoir"
};
dictionary["thank you"] = "merci"; // OK
dictionary[42] = "number"; // Works at runtime (42 is coerced to "42")
// TypeScript will catch assigning wrong value types:
dictionary["hello"] = 123; // Error: Type 'number' is not assignable to type 'string'
Practical examples
Order object
Loading code...
let order: {
pizzaName: string;
quantity: number;
total: number;
extras?: string[];
} = {
pizzaName: "Pepperoni",
quantity: 2,
total: 25.98,
extras: ["peppers", "mushrooms"]
};
console.log(order);
Functions with object parameters
Loading code...
function createPizza(pizza: { name: string; price: number }): string {
return `Created pizza: ${pizza.name} for $${pizza.price}`;
}
let correctPizza = createPizza({name: "Veg", price: 15.95 }); // works- types are correct
let incorrectPizza = createPizza({name: "Veg", price: "15.95" }); // error: Type 'string' is not assignable to type 'number'
Objects with type annotations provide structure and type safety to your data. Coming next, we cover how to add type annotations to functions in more detail.