Optional Syntax
Optional properties are marked with the ? suffix, indicating that objects implementing the interface may or may not include these properties.
About 963 wordsAbout 12 min
2025-08-05
Note
Optional properties and advanced interface features enable TypeScript to model real-world scenarios where objects may have varying sets of properties. These features provide flexibility while maintaining type safety and enabling sophisticated type patterns.
Optional properties allow interfaces to define shapes where certain properties may or may not be present, enabling flexible object structures.
Optional Syntax
Optional properties are marked with the ? suffix, indicating that objects implementing the interface may or may not include these properties.
Readonly Properties
Readonly properties prevent modification after object creation, enforcing immutability and preventing accidental changes to important data.
Property Modifiers
TypeScript provides various property modifiers including readonly, optional, and access modifiers that control how properties can be used and modified.
Optional properties enable flexible object structures while maintaining type safety through proper checking.
Basic Optional Properties
Use the ? suffix to mark properties as optional, allowing objects to implement interfaces without providing all properties.
interface User {
id: number;
name: string;
email?: string; // Optional property
phone?: string; // Optional property
age?: number; // Optional property
}
// All valid User objects
const user1: User = { id: 1, name: "John" };
const user2: User = { id: 2, name: "Jane", email: "jane@example.com" };
const user3: User = { id: 3, name: "Bob", email: "bob@example.com", age: 30 };Step 1
Checking Optional Properties
Safely check for optional properties before using them to avoid runtime errors.
function displayUserInfo(user: User): void {
console.log(`User: ${user.name} (ID: ${user.id})`);
// Safe checking of optional properties
if (user.email) {
console.log(`Email: ${user.email}`);
}
if (user.age !== undefined) {
console.log(`Age: ${user.age}`);
}
// Using optional chaining
console.log(`Email length: ${user.email?.length ?? 'N/A'}`);
}Step 2
Default Values for Optional Properties
Provide default values for optional properties in function parameters and object destructuring.
interface Config {
timeout?: number;
retries?: number;
debug?: boolean;
}
function createDefaultConfig(config: Config = {}): Config {
return {
timeout: config.timeout ?? 5000,
retries: config.retries ?? 3,
debug: config.debug ?? false
};
}
// Using object destructuring with defaults
function processConfig({ timeout = 5000, retries = 3, debug = false }: Config = {}) {
console.log(`Timeout: ${timeout}, Retries: ${retries}, Debug: ${debug}`);
}Step 3
Readonly properties enforce immutability, preventing accidental modification of important data.
Readonly Interface Properties Mark properties as readonly to prevent modification after object creation.
interface ImmutableUser {
readonly id: number;
readonly name: string;
readonly createdAt: Date;
email?: string; // Optional readonly properties
}
const user: ImmutableUser = {
id: 1,
name: "Alice",
createdAt: new Date(),
email: "alice@example.com"
};
user.id = 2; // Error: Cannot assign to 'id' because it is read-only
user.name = "Bob"; // Error: Cannot assign to 'name' because it is read-only
user.email = "new@example.com"; // Error: Cannot assign to 'email' because it is read-onlyReadonly Utility Type Use the built-in Readonly<T> utility type to make all properties of an interface readonly.
interface MutableUser {
id: number;
name: string;
email?: string;
}
type ImmutableUser = Readonly<MutableUser>;
const user: ImmutableUser = {
id: 1,
name: "Alice",
email: "alice@example.com"
};
// All properties are now readonly
user.name = "Bob"; // Error: Cannot assign to 'name' because it is read-onlyReadonly Arrays and Tuples TypeScript also supports readonly arrays and tuples for immutable collections.
const readonlyArray: readonly number[] = [1, 2, 3];
readonlyArray[0] = 4; // Error: Index signature in type 'readonly number[]' only permits reading
const readonlyTuple: readonly [string, number] = ["hello", 42];
readonlyTuple[0] = "world"; // Error: Cannot assign to '0' because it is read-onlyComplex interface patterns enable sophisticated type modeling for real-world scenarios.
// Partial interface for updates
interface UserUpdate {
name?: string;
email?: string;
age?: number;
}
// Function with optional and required parameters
interface Database {
insert(user: Omit<User, 'id'>): User;
update(id: number, updates: Partial<User>): User | null;
delete(id: number): boolean;
find(criteria: Partial<User>): User[];
}
// Discriminated unions with optional properties
type ApiResponse<T> =
| { success: true; data: T; metadata?: ResponseMetadata }
| { success: false; error: string; code?: number };
interface ResponseMetadata {
timestamp: Date;
requestId: string;
version: string;
}
// Default property values
interface ButtonProps {
text: string;
onClick: () => void;
disabled?: boolean;
variant?: 'primary' | 'secondary' | 'danger';
size?: 'small' | 'medium' | 'large';
}
function createButton({
text,
onClick,
disabled = false,
variant = 'primary',
size = 'medium'
}: ButtonProps): HTMLButtonElement {
const button = document.createElement('button');
button.textContent = text;
button.onclick = onClick;
button.disabled = disabled;
// Apply styling based on variant and size
button.className = `btn btn-${variant} btn-${size}`;
return button;
}TypeScript provides built-in utility types for working with optional properties:
interface CompleteUser {
id: number;
name: string;
email: string;
age: number;
}
// Make all properties optional
type PartialUser = Partial<CompleteUser>;
// Equivalent to:
// interface PartialUser {
// id?: number;
// name?: string;
// email?: string;
// age?: number;
// }
// Make specific properties optional
type UserWithoutId = Omit<CompleteUser, 'id'>;
// Equivalent to:
// interface UserWithoutId {
// name: string;
// email: string;
// age: number;
// }
// Pick specific properties
type UserContactInfo = Pick<CompleteUser, 'name' | 'email'>;
// Equivalent to:
// interface UserContactInfo {
// name: string;
// email: string;
// }
// Required properties (inverse of optional)
type RequiredUser = Required<PartialUser>;
// Makes all properties required againAn interface property marked with the ? suffix that may or may not be present in objects implementing the interface, providing flexibility in object structure.
An interface property marked with the readonly keyword that cannot be modified after the object is created, enforcing immutability and preventing accidental changes.
A TypeScript utility type that makes all properties of an interface optional, useful for update operations and partial object specifications.
A value provided in a function parameter or destructuring assignment that is used when no value or undefined is passed for that parameter.
3d51f-feat: introducing generic types and propertieson Copyright Ownership:WARREN Y.F. LONG
License under:Attribution-NonCommercial-NoDerivatives 4.0 International (CC-BY-NC-ND-4.0)