TypeScript Syntax
Introduction
TypeScript extends JavaScript by adding static type definitions, allowing developers to catch errors earlier in the development process. Understanding TypeScript syntax is essential for writing type-safe code that's easier to maintain and refactor. This guide will walk you through the basic syntax elements of TypeScript, from variable declarations to more advanced type features.
Basic Types
TypeScript supports all the primitive types available in JavaScript with the addition of type annotations.
Type Annotations
Type annotations in TypeScript are a way to explicitly specify the type of a variable, function parameter, or return value.
// Type annotation for variables
let name: string = "John";
let age: number = 25;
let isActive: boolean = true;
let nullValue: null = null;
let undefinedValue: undefined = undefined;
The colon (:
) followed by a type is how you annotate types in TypeScript.
Number Type
The number
type represents all numeric values in TypeScript, including integers, floats, and special values like NaN
and Infinity
.
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
let floating: number = 3.14;
String Type
The string
type represents text data in TypeScript.
let firstName: string = "John";
let lastName: string = 'Doe';
let fullName: string = `${firstName} ${lastName}`; // Template string
Boolean Type
The boolean
type has only two possible values: true
and false
.
let isDone: boolean = false;
let isCompleted: boolean = true;
Array Type
Arrays in TypeScript can be written in two ways:
// Using the type followed by []
let numbers: number[] = [1, 2, 3, 4, 5];
// Using generic array type
let strings: Array<string> = ["hello", "world"];
Tuple Type
Tuples allow you to express an array with a fixed number of elements whose types are known.
// Declare a tuple
let person: [string, number] = ["John", 25];
// Accessing tuple elements
console.log(person[0]); // Output: "John"
console.log(person[1]); // Output: 25
Enum Type
Enums allow you to define a set of named constants.
enum Color {
Red,
Green,
Blue
}
// Using the enum
let favoriteColor: Color = Color.Blue;
console.log(favoriteColor); // Output: 2 (index of Blue)
// Enums can also have custom values
enum Status {
Pending = "PENDING",
Approved = "APPROVED",
Rejected = "REJECTED"
}
let currentStatus: Status = Status.Approved;
console.log(currentStatus); // Output: "APPROVED"
Any Type
The any
type allows you to work with values that you might not know the type of at compile time.
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // now it's a boolean
While any
is flexible, it defeats the purpose of type checking. Use it sparingly.
Unknown Type
Similar to any
, but safer because you can't perform operations on an unknown
value without type checking first.
let userInput: unknown;
userInput = 5;
userInput = "hello";
// Checking type before operations
if (typeof userInput === "string") {
console.log(userInput.toUpperCase()); // OK
}
Void Type
void
is used as the return type for functions that don't return a value.
function logMessage(message: string): void {
console.log(message);
// no return statement needed
}
Never Type
The never
type represents values that never occur. It's used for functions that never return or always throw exceptions.
function throwError(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {
// code that never terminates
}
}
Type Inference
TypeScript can often infer types based on the context, allowing you to omit explicit type annotations.
// TypeScript infers the type as 'string'
let message = "Hello, World!";
// TypeScript infers the return type as 'number'
function add(a: number, b: number) {
return a + b;
}
Variable Declarations
TypeScript supports JavaScript's var
, let
, and const
declarations with added type safety.
Let & Const
// 'let' allows the variable to be reassigned
let counter: number = 0;
counter = 1; // Valid
// 'const' creates an immutable binding
const maxAttempts: number = 3;
// maxAttempts = 5; // Error: Cannot reassign a constant
Type Assertions
Type assertions are a way to tell the compiler "trust me, I know what I'm doing" when you have more information about a value's type than TypeScript can infer.
// Using angle-bracket syntax
let someValue: unknown = "this is a string";
let strLength: number = (<string>someValue).length;
// Using 'as' syntax (preferred in JSX)
let anotherValue: unknown = "another string";
let anotherLength: number = (anotherValue as string).length;
Functions in TypeScript
Functions in TypeScript can have type annotations for parameters and return values.
Function Declarations
// Function with parameter types and return type
function greet(name: string): string {
return `Hello, ${name}!`;
}
// Function with optional parameter
function buildName(firstName: string, lastName?: string): string {
if (lastName) {
return `${firstName} ${lastName}`;
}
return firstName;
}
// Function with default parameter
function createGreeting(name: string, greeting: string = "Hello"): string {
return `${greeting}, ${name}!`;
}
Arrow Functions
// Arrow function with type annotations
const multiply = (a: number, b: number): number => a * b;
// With inferred return type
const divide = (a: number, b: number) => a / b;
Rest Parameters
function sum(...numbers: number[]): number {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // Output: 10
Interfaces
Interfaces define the contract for objects in TypeScript.
// Basic interface
interface User {
id: number;
name: string;
email: string;
isActive: boolean;
}
// Using the interface
const newUser: User = {
id: 1,
name: "John Doe",
email: "[email protected]",
isActive: true
};
// Interface with optional properties
interface Product {
id: number;
name: string;
price: number;
description?: string; // Optional property
}
// Interface extending another interface
interface Employee extends User {
employeeId: string;
department: string;
}
Classes
TypeScript adds type annotations to traditional JavaScript classes.
class Person {
// Class properties with type annotations
name: string;
age: number;
// Constructor
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// Method with return type
greet(): string {
return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
}
}
// Creating an instance
const alice = new Person("Alice", 30);
console.log(alice.greet()); // Output: Hello, my name is Alice and I am 30 years old.
Access Modifiers
TypeScript introduces access modifiers: public
, private
, and protected
.
class BankAccount {
public owner: string;
private balance: number;
protected accountNumber: string;
constructor(owner: string, balance: number, accountNumber: string) {
this.owner = owner;
this.balance = balance;
this.accountNumber = accountNumber;
}
// Public method to access private property
public getBalance(): number {
return this.balance;
}
// Method to modify private property
public deposit(amount: number): void {
this.balance += amount;
}
}
const account = new BankAccount("John Doe", 1000, "123456789");
console.log(account.owner); // Accessible: "John Doe"
// console.log(account.balance); // Error: 'balance' is private
// console.log(account.accountNumber); // Error: 'accountNumber' is protected
console.log(account.getBalance()); // Accessible through method: 1000
Type Aliases
Type aliases create a new name for a type and can be used to name primitive types, union types, tuples, and other complex types.
// Simple type alias
type Point = {
x: number;
y: number;
};
// Using the type alias
const origin: Point = { x: 0, y: 0 };
// Union type with type alias
type Result = string | number;
function processResult(value: Result) {
if (typeof value === "string") {
return value.toUpperCase();
} else {
return value * 2;
}
}
Union and Intersection Types
Union Types
Union types allow a value to be one of several types.
// Variable can be either string or number
let id: string | number;
id = 101; // Valid
id = "ABC"; // Also valid
// id = true; // Error: Type 'boolean' is not assignable to type 'string | number'
Intersection Types
Intersection types combine multiple types into one.
// Combining types
type Employee = {
id: number;
name: string;
};
type Manager = {
employees: Employee[];
department: string;
};
// Intersection type
type EmployeeManager = Employee & Manager;
const manager: EmployeeManager = {
id: 1,
name: "John Doe",
employees: [{ id: 2, name: "Jane Smith" }],
department: "Engineering"
};
Practical Example: Building a Task Management System
Let's apply what we've learned to build a simple task management system:
// Define task status as an enum
enum TaskStatus {
Todo = "TODO",
InProgress = "IN_PROGRESS",
Done = "DONE"
}
// Define the Task interface
interface Task {
id: number;
title: string;
description?: string;
status: TaskStatus;
dueDate?: Date;
tags: string[];
}
// Define a TaskManager class
class TaskManager {
private tasks: Task[] = [];
private nextId: number = 1;
// Add a new task
addTask(title: string, description?: string, dueDate?: Date, tags: string[] = []): Task {
const newTask: Task = {
id: this.nextId++,
title,
description,
status: TaskStatus.Todo,
dueDate,
tags
};
this.tasks.push(newTask);
return newTask;
}
// Get all tasks
getAllTasks(): Task[] {
return this.tasks;
}
// Get tasks by status
getTasksByStatus(status: TaskStatus): Task[] {
return this.tasks.filter(task => task.status === status);
}
// Update task status
updateTaskStatus(id: number, status: TaskStatus): Task | undefined {
const task = this.tasks.find(t => t.id === id);
if (task) {
task.status = status;
}
return task;
}
// Delete a task
deleteTask(id: number): boolean {
const initialLength = this.tasks.length;
this.tasks = this.tasks.filter(task => task.id !== id);
return initialLength > this.tasks.length;
}
}
// Usage example
const taskManager = new TaskManager();
// Add tasks
taskManager.addTask("Learn TypeScript", "Study the syntax and features", new Date(2023, 11, 31), ["learning", "programming"]);
taskManager.addTask("Build a project", "Apply TypeScript in a real project", undefined, ["project", "coding"]);
// Update task status
taskManager.updateTaskStatus(1, TaskStatus.InProgress);
// Get all tasks
const allTasks = taskManager.getAllTasks();
console.log("All tasks:", allTasks);
// Get tasks in progress
const inProgressTasks = taskManager.getTasksByStatus(TaskStatus.InProgress);
console.log("In progress tasks:", inProgressTasks);
Output:
All tasks: [
{
id: 1,
title: 'Learn TypeScript',
description: 'Study the syntax and features',
status: 'IN_PROGRESS',
dueDate: 2023-12-31T00:00:00.000Z,
tags: [ 'learning', 'programming' ]
},
{
id: 2,
title: 'Build a project',
description: 'Apply TypeScript in a real project',
status: 'TODO',
tags: [ 'project', 'coding' ]
}
]
In progress tasks: [
{
id: 1,
title: 'Learn TypeScript',
description: 'Study the syntax and features',
status: 'IN_PROGRESS',
dueDate: 2023-12-31T00:00:00.000Z,
tags: [ 'learning', 'programming' ]
}
]
Summary
In this guide, we've covered the essential syntax of TypeScript:
- Basic types:
string
,number
,boolean
, arrays, tuples, and more - Type annotations and type inference
- Variable declarations with
let
andconst
- Functions with parameter types and return types
- Interfaces for defining object structures
- Classes with access modifiers
- Type aliases, union types, and intersection types
Understanding TypeScript syntax is the foundation for writing type-safe applications. By leveraging TypeScript's static typing, you can catch errors during development rather than at runtime, making your code more robust and maintainable.
Exercises
-
Create a
Person
interface with properties for name, age, and email. Then create an array ofPerson
objects and write a function that filters people by age. -
Define an enum for days of the week and write a function that takes a day as input and returns whether it's a weekday or weekend.
-
Create a generic function that can reverse any array, preserving the type of its elements.
-
Extend the task management system example to include priority levels for tasks and the ability to sort tasks by priority.
Additional Resources
- TypeScript Official Documentation
- TypeScript Playground - Try TypeScript in your browser
- TypeScript Deep Dive - A comprehensive free book
- TypeScript Cheat Sheet
Happy coding with TypeScript!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)