- TypeScript Tutorial
- TypeScript Home
- TypeScript Introduction
- TypeScript Setup
- TypeScript First Program
- TypeScript vs JavaScript
- TypeScript Data Types
- TypeScript Type Inference
- TypeScript Type Annotations
- TypeScript Interfaces
- TypeScript Enums
- TypeScript Type Aliases
- TypeScript Type Assertions
- TypeScript Variables
- TypeScript Functions
- TypeScript Functions
- TypeScript Optional Parameters
- TypeScript Default Parameters
- TypeScript Rest Parameters
- TypeScript Arrow Functions
- Classes and Objects
- Introduction to Classes
- Properties and Methods
- Access Modifiers
- Static Members
- Inheritance
- Abstract Classes
- Interfaces vs Classes
- Advanced Types
- TypeScript Union Types
- TypeScript Intersection Types
- TypeScript Literal Types
- TypeScript Nullable Types
- TypeScript Type Guards
- TypeScript Discriminated Unions
- TypeScript Index Signatures
- TypeScript Generics
- Introduction to Generics
- TypeScript Generic Functions
- TypeScript Generic Classes
- TypeScript Generic Constraints
- TypeScript Modules
- Introduction to Modules
- TypeScript Import and Export
- TypeScript Default Exports
- TypeScript Namespace
- Decorators
- Introduction to Decorators
- TypeScript Class Decorators
- TypeScript Method Decorators
- TypeScript Property Decorators
- TypeScript Parameter Decorators
- Configuration
- TypeScript tsconfig.json File
- TypeScript Compiler Options
- TypeScript Strict Mode
- TypeScript Watch Mode
Properties and Methods in TypeScript
In TypeScript, classes serve as blueprints for creating objects. To make these objects useful, we need two things: Properties to store data (the "state") and Methods to define actions (the "behavior"). While JavaScript handles these concepts dynamically, TypeScript adds a layer of static typing. This means you can catch bugs like trying to call a method that doesn't exist or assigning a string to a number before you even run your code.
Defining Properties
Properties are variables that live inside a class. In TypeScript, you explicitly declare these properties and their types at the top of the class body. This makes it immediately clear to any developer what data a class is responsible for managing.
class Car {
make: string;
model: string;
year: number;
constructor(make: string, model: string, year: number) {
this.make = make;
this.model = model;
this.year = year;
}
}
const myCar = new Car("Toyota", "Corolla", 2020);
console.log(myCar.make); // Output: Toyota
In this example, make, model, and year are properties. By typing them, we ensure that a Car can never accidentally have a "year" that is a string, which could break date-based logic elsewhere in your app.
public or private) before the parameter name: constructor(public make: string) {}.
Defining Methods
Methods are functions defined inside a class that operate on the object's data. They allow objects to "do" things. In TypeScript, you should always define the types for method parameters and the return value to maintain a strict contract throughout your codebase.
class Rectangle {
width: number;
height: number;
constructor(width: number, height: number) {
this.width = width;
this.height = height;
}
// A method that calculates data based on properties
calculateArea(): number {
return this.width * this.height;
}
}
const rect = new Rectangle(5, 10);
console.log(rect.calculateArea()); // Output: 50
By specifying : number as the return type for calculateArea, TypeScript will alert you if you accidentally try to return a string or forget the return statement entirely.
Read-Only Properties
Sometimes you want a property to be set once (usually during initialization) and never changed again. This is common for unique IDs, configuration settings, or hardware specifications. Use the readonly keyword to enforce this immutability.
class Product {
readonly id: string;
name: string;
constructor(id: string, name: string) {
this.id = id;
this.name = name;
}
}
const product = new Product("8f92-b21a", "Laptop");
console.log(product.id); // Output: 8f92-b21a
// product.id = "new-id"; // Error: Cannot assign to 'id' because it is a read-only property.
readonly check only happens at compile-time. If you are working in a mixed environment or using any, the underlying JavaScript will still allow the value to be changed at runtime unless you use other JS features like Object.freeze().
Optional Properties
In real-world applications, not all data is available upfront. TypeScript allows you to mark properties as optional using the ? symbol. This tells the compiler that the property might be a specific type, or it might be undefined.
class Employee {
id: number;
name: string;
department?: string; // This property is optional
constructor(id: number, name: string, department?: string) {
this.id = id;
this.name = name;
this.department = department;
}
}
const emp1 = new Employee(1, "John");
const emp2 = new Employee(2, "Jane", "Engineering");
console.log(emp1.department); // Output: undefined
emp1.department.toLowerCase(), your code will crash because department is undefined. Always use optional chaining (emp1.department?.toLowerCase()).
Method Overloading
TypeScript supports method overloading, which allows a single method to handle different types or numbers of arguments. Note that in TypeScript, you provide multiple "signatures" but only one actual implementation that must handle all cases.
class Logger {
// Overload signatures
log(message: string): void;
log(message: string, code: number): void;
// Single implementation signature
log(message: string, code?: number): void {
if (code) {
console.log(`[Error ${code}]: ${message}`);
} else {
console.log(`[Info]: ${message}`);
}
}
}
const myLogger = new Logger();
myLogger.log("System started"); // Output: [Info]: System started
myLogger.log("Connection failed", 500); // Output: [Error 500]: Connection failed
This is extremely useful when building APIs or libraries where you want to provide a flexible interface for other developers without writing multiple method names like logWithMessage and logWithMessageAndCode.
Static Properties and Methods
Static members belong to the class itself, not to any specific instance (object) of the class. They are useful for utility functions or global constants that relate to the class but don't require data from a specific instance.
class AppConfig {
static apiEndpoint: string = "https://api.example.com/v1";
static getFullUrl(resource: string): string {
return `${this.apiEndpoint}/${resource}`;
}
}
// Access without creating an instance
console.log(AppConfig.apiEndpoint);
console.log(AppConfig.getFullUrl("users"));
Access Modifiers
Access modifiers control who can see and modify the members of your class. This is the cornerstone of Encapsulation, a principle that keeps your internal logic hidden and safe from outside interference.
public: The default. Anyone can access it.private: Only code inside the class can see it. Use this for internal state.protected: Only the class and its subclasses (children) can see it.
class Person {
public name: string;
private socialSecurityNumber: string;
constructor(name: string, ssn: string) {
this.name = name;
this.socialSecurityNumber = ssn;
}
public getMaskedSSN(): string {
return `***-**-${this.socialSecurityNumber.slice(-4)}`;
}
}
const person = new Person("Alice", "123-45-6789");
console.log(person.name); // Alice (Accessible)
console.log(person.getMaskedSSN()); // ***-**-6789 (Accessible)
// console.log(person.socialSecurityNumber); // Error: Private property!
private or protected. Only make them public if you are absolutely sure they need to be accessed from outside the class.
Summary
Properties and methods are the building blocks of object-oriented programming in TypeScript. By leveraging types, access modifiers, and read-only constraints, you can create code that is self-documenting and much harder to break. Understanding how to hide sensitive data with private and provide flexible interfaces with overloading is what separates a beginner from a professional TypeScript developer.