Quick Overview
`?` makes a property optional, which adds `undefined` to its type rather than removing the key. That is why reading it still needs a check even after the shape is declared.
Objects are the foundation of JavaScript applications. TypeScript allows you to define explicit object shape contracts to ensure properties and methods match expected schemas.
type Alias KeywordA Type Alias creates a reusable custom name for any type definition (object shapes, unions, primitives, or tuples):
// Define a reusable object shape type alias
type UserProfile = {
readonly id: number; // Readonly property (cannot be reassigned)
name: string;
email: string;
bio?: string; // Optional property (string | undefined)
};
const user1: UserProfile = {
id: 101,
name: "Alex",
email: "alex@devloom.dev",
};
// user1.id = 999; // Error: Cannot assign to 'id' because it is a read-only property
Type aliases can be composed and nested cleanly:
type Address = {
city: string;
country: string;
};
type Employee = {
id: number;
name: string;
address: Address; // Nested type alias reference
};
When assigning an object literal directly to a typed variable, TypeScript performs Excess Property Checks to catch typo bugs:
type Point = { x: number; y: number };
// Error: 'z' does not exist in type 'Point'
// const p: Point = { x: 10, y: 20, z: 30 };
user.bio.length) without null checking throws a compile error because bio might be undefined. Use optional chaining user.bio?.length.Use type aliases for custom data structures. Next, let me compare Interfaces versus Type Aliases!
TypeScript erases entirely at build time, so a `string` annotation produces no runtime check whatsoever. A value arriving from an API is whatever the server actually sent, regardless of what the annotation claims.
`let x = "GET"` infers `string` because the binding can change; `const x = "GET"` infers the literal `"GET"`. That widening rule is why object properties need `as const` to stay narrow.
`string[]` is any number of strings; `[string, number]` is exactly two, in that order. `readonly` removes the mutating methods at compile time, so `push` becomes a type error rather than a runtime surprise.