Skip to main content

TypeScript Operators

Introduction

Operators are symbols that perform operations on operands (values and variables). TypeScript includes all JavaScript operators along with some additional operators specifically for TypeScript's type system. Understanding these operators is essential for writing effective TypeScript code and leveraging the full power of the language.

In this tutorial, we'll cover:

  • Arithmetic operators
  • Comparison operators
  • Logical operators
  • Assignment operators
  • Type operators
  • Bitwise operators
  • String operators
  • Special operators in TypeScript

Arithmetic Operators

Arithmetic operators perform mathematical operations on numeric values.

OperatorDescriptionExample
+Addition5 + 3 equals 8
-Subtraction5 - 3 equals 2
*Multiplication5 * 3 equals 15
/Division6 / 3 equals 2
%Modulus (remainder)5 % 2 equals 1
++Incrementlet x = 5; x++; results in x being 6
--Decrementlet x = 5; x--; results in x being 4
**Exponentiation2 ** 3 equals 8

Let's see these in action:

typescript
// Basic arithmetic operations
let a: number = 10;
let b: number = 3;

let sum: number = a + b; // 13
let difference: number = a - b; // 7
let product: number = a * b; // 30
let quotient: number = a / b; // 3.3333...
let remainder: number = a % b; // 1
let power: number = a ** b; // 1000 (10^3)

// Increment and decrement
let count: number = 1;
console.log(count++); // Outputs 1, then increments to 2
console.log(++count); // Increments to 3, then outputs 3
console.log(count--); // Outputs 3, then decrements to 2
console.log(--count); // Decrements to 1, then outputs 1

Comparison Operators

Comparison operators compare two values and return a boolean result.

OperatorDescriptionExample
==Equal (value)5 == "5" is true
===Strict equal (value and type)5 === "5" is false
!=Not equal5 != "6" is true
!==Strict not equal5 !== "5" is true
>Greater than5 > 3 is true
<Less than5 < 3 is false
>=Greater than or equal5 >= 5 is true
<=Less than or equal5 <= 3 is false

Example:

typescript
let x: number = 10;
let y: number = 5;
let z: string = "10";

console.log(x == 10); // true
console.log(x == +z); // true (string "10" is converted to number 10)
console.log(x === +z); // true (after conversion, both value and type match)
console.log(x === z); // false (different types)
console.log(x != 5); // true
console.log(x !== 10); // false
console.log(x > y); // true
console.log(x < y); // false
console.log(y >= 5); // true
console.log(y <= 5); // true

Logical Operators

Logical operators perform logical operations and return a boolean value.

OperatorDescriptionExample
&&Logical ANDtrue && false is false
||Logical ORtrue || false is true
!Logical NOT!true is false
??Nullish Coalescingnull ?? "default" is "default"

Example:

typescript
let isMember: boolean = true;
let hasDiscount: boolean = false;
let name: string | null = null;
let defaultName: string = "Guest";

// Logical AND
console.log(isMember && hasDiscount); // false

// Logical OR
console.log(isMember || hasDiscount); // true

// Logical NOT
console.log(!isMember); // false

// Nullish coalescing (returns right-hand side if left is null or undefined)
console.log(name ?? defaultName); // "Guest"

// Combining operators
let isEligible: boolean = (isMember || hasDiscount) && age >= 18;

Assignment Operators

Assignment operators assign values to variables.

OperatorDescriptionExample
=Assignmentx = 5
+=Addition assignmentx += 3 same as x = x + 3
-=Subtraction assignmentx -= 3 same as x = x - 3
*=Multiplication assignmentx *= 3 same as x = x * 3
/=Division assignmentx /= 3 same as x = x / 3
%=Modulus assignmentx %= 3 same as x = x % 3
**=Exponentiation assignmentx **= 3 same as x = x ** 3

Example:

typescript
let value: number = 10;

value += 5; // value is now 15
console.log(value);

value -= 3; // value is now 12
console.log(value);

value *= 2; // value is now 24
console.log(value);

value /= 6; // value is now 4
console.log(value);

value %= 3; // value is now 1 (remainder of 4/3)
console.log(value);

value = 2;
value **= 3; // value is now 8 (2^3)
console.log(value);

Type Operators

TypeScript provides special operators for working with types.

typeof Operator

The typeof operator returns a string indicating the type of the operand.

typescript
let str = "Hello";
let num = 42;
let bool = true;
let undef = undefined;
let nil = null;
let obj = {};
let arr: number[] = [1, 2, 3];
let func = () => console.log("Hello");

console.log(typeof str); // "string"
console.log(typeof num); // "number"
console.log(typeof bool); // "boolean"
console.log(typeof undef); // "undefined"
console.log(typeof nil); // "object" (historical JavaScript quirk)
console.log(typeof obj); // "object"
console.log(typeof arr); // "object" (arrays are objects in JavaScript)
console.log(typeof func); // "function"

Type Guards with typeof

In TypeScript, typeof can be used as a type guard:

typescript
function padValue(value: string | number, padding: number): string {
if (typeof value === "string") {
// TypeScript knows value is a string in this block
return " ".repeat(padding) + value;
} else {
// TypeScript knows value is a number in this block
return " ".repeat(padding) + value.toString();
}
}

console.log(padValue("Hello", 3)); // " Hello"
console.log(padValue(42, 3)); // " 42"

instanceof Operator

The instanceof operator checks if an object is an instance of a specific class or constructor function.

typescript
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
}

class Dog extends Animal {
breed: string;
constructor(name: string, breed: string) {
super(name);
this.breed = breed;
}
}

const generic = new Animal("Generic Animal");
const rover = new Dog("Rover", "Labrador");

console.log(generic instanceof Animal); // true
console.log(generic instanceof Dog); // false
console.log(rover instanceof Animal); // true (Dog inherits from Animal)
console.log(rover instanceof Dog); // true

keyof Operator

The keyof operator returns a union type of all property names of a given type.

typescript
interface User {
id: number;
name: string;
email: string;
}

// KeysOfUser is "id" | "name" | "email"
type KeysOfUser = keyof User;

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[K];
}

const user: User = {
id: 1,
name: "John Doe",
email: "[email protected]"
};

// TypeScript knows that the result will be a number
const id = getProperty(user, "id");

// TypeScript knows that the result will be a string
const name = getProperty(user, "name");

// This would cause a compile-time error
// const age = getProperty(user, "age"); // Error: "age" is not assignable to parameter of type keyof User

in Operator

The in operator checks if a property exists in an object.

typescript
interface Admin {
id: number;
name: string;
privileges: string[];
}

interface Employee {
id: number;
name: string;
startDate: Date;
}

type UnknownEmployee = Employee | Admin;

function printEmployeeInfo(emp: UnknownEmployee) {
console.log(`Name: ${emp.name}`);

if ("privileges" in emp) {
// TypeScript knows that emp is Admin in this block
console.log(`Privileges: ${emp.privileges.join(', ')}`);
}

if ("startDate" in emp) {
// TypeScript knows that emp is Employee in this block
console.log(`Start Date: ${emp.startDate.toISOString()}`);
}
}

const emp1: Admin = {
id: 1,
name: "John",
privileges: ["server-admin", "user-admin"]
};

printEmployeeInfo(emp1);
// Output:
// Name: John
// Privileges: server-admin, user-admin

Bitwise Operators

Bitwise operators perform operations on binary representations of numbers.

OperatorDescriptionExample
&Bitwise AND5 & 3 is 1
|Bitwise OR5 | 3 is 7
^Bitwise XOR5 ^ 3 is 6
~Bitwise NOT~5 is -6
<<Left shift5 << 1 is 10
>>Right shift5 >> 1 is 2
>>>Unsigned right shift5 >>> 1 is 2

Example:

typescript
// 5 in binary:  101
// 3 in binary: 011
let a: number = 5;
let b: number = 3;

console.log(a & b); // 001 in binary = 1
console.log(a | b); // 111 in binary = 7
console.log(a ^ b); // 110 in binary = 6
console.log(~a); // -6 (invert all bits and add 1)
console.log(a << 1); // 1010 in binary = 10 (shift left 1 bit)
console.log(a >> 1); // 010 in binary = 2 (shift right 1 bit)
console.log(a >>> 1); // 010 in binary = 2 (shift right 1 bit, fill with 0s)

Bitwise operators are less commonly used in everyday TypeScript but are important for low-level operations, flags, or performance optimization.

String Operators

The + operator can be used to concatenate strings.

typescript
let firstName: string = "John";
let lastName: string = "Doe";

// String concatenation
let fullName: string = firstName + " " + lastName;
console.log(fullName); // "John Doe"

// String concatenation with assignment
let greeting: string = "Hello, ";
greeting += fullName;
console.log(greeting); // "Hello, John Doe"

Optional Chaining Operator (?.)

The optional chaining operator allows you to safely access properties of an object that might be null or undefined.

typescript
interface User {
id: number;
name: string;
contact?: {
email?: string;
phone?: string;
};
}

const user1: User = {
id: 1,
name: "John"
};

const user2: User = {
id: 2,
name: "Jane",
contact: {
email: "[email protected]"
}
};

// Without optional chaining (might cause runtime error)
// const email1 = user1.contact.email; // Error: Cannot read property 'email' of undefined

// With optional chaining (returns undefined if any part of the chain is null/undefined)
const email1 = user1.contact?.email;
console.log(email1); // undefined

const email2 = user2.contact?.email;
console.log(email2); // "[email protected]"

const phone2 = user2.contact?.phone;
console.log(phone2); // undefined

Real-World Examples

Building a Filter Function with Type Guards

typescript
// Define various data types
interface Product {
id: number;
name: string;
price: number;
}

interface User {
id: number;
name: string;
email: string;
}

type Entity = Product | User;

// Filter an array of entities based on their type
function filterProducts(entities: Entity[]): Product[] {
return entities.filter((entity): entity is Product => 'price' in entity);
}

function filterUsers(entities: Entity[]): User[] {
return entities.filter((entity): entity is User => 'email' in entity);
}

// Test data
const data: Entity[] = [
{ id: 1, name: "Product 1", price: 99.99 },
{ id: 2, name: "John Doe", email: "[email protected]" },
{ id: 3, name: "Product 2", price: 149.99 },
{ id: 4, name: "Jane Smith", email: "[email protected]" }
];

const products = filterProducts(data);
console.log("Products:", products);
/*
Products: [
{ id: 1, name: 'Product 1', price: 99.99 },
{ id: 3, name: 'Product 2', price: 149.99 }
]
*/

const users = filterUsers(data);
console.log("Users:", users);
/*
Users: [
{ id: 2, name: 'John Doe', email: '[email protected]' },
{ id: 4, name: 'Jane Smith', email: '[email protected]' }
]
*/

Tax Calculator with Arithmetic and Logical Operators

typescript
interface PurchaseItem {
name: string;
price: number;
taxExempt?: boolean;
discountEligible?: boolean;
}

function calculateTotal(items: PurchaseItem[], taxRate: number, discount: number): number {
let subtotal = 0;
let taxAmount = 0;

for (const item of items) {
subtotal += item.price;

// Apply tax if not exempt
if (!item.taxExempt) {
taxAmount += item.price * (taxRate / 100);
}
}

// Check if any item is eligible for discount
const hasDiscountItem = items.some(item => item.discountEligible === true);

// Apply discount if eligible
let finalTotal = subtotal + taxAmount;
if (hasDiscountItem) {
finalTotal *= (1 - discount / 100);
}

// Round to 2 decimal places
return Math.round(finalTotal * 100) / 100;
}

// Example usage
const shoppingCart: PurchaseItem[] = [
{ name: "Book", price: 15.99, taxExempt: true },
{ name: "Laptop", price: 999.99, discountEligible: true },
{ name: "Headphones", price: 59.99 }
];

const total = calculateTotal(shoppingCart, 8.5, 10);
console.log(`Total: $${total}`); // Total: $1025.38

Permission System with Bitwise Operators

typescript
// Define permissions as bit flags
const enum Permission {
None = 0, // 000000
Read = 1 << 0, // 000001
Write = 1 << 1, // 000010
Execute = 1 << 2, // 000100
Delete = 1 << 3, // 001000
Admin = 1 << 4, // 010000
SuperUser = 1 << 5 // 100000
}

// Create compound permissions
const ReadWrite = Permission.Read | Permission.Write; // 000011
const FullAccess = Permission.Read | Permission.Write |
Permission.Execute | Permission.Delete; // 001111
const AdminAccess = FullAccess | Permission.Admin; // 011111

function checkPermission(userPermissions: Permission, requiredPermission: Permission): boolean {
// Using bitwise AND to check if user has the required permission
return (userPermissions & requiredPermission) === requiredPermission;
}

// Example usage
const userPermissions = ReadWrite | Permission.Delete; // User can read, write, and delete

console.log("Can read?", checkPermission(userPermissions, Permission.Read)); // true
console.log("Can execute?", checkPermission(userPermissions, Permission.Execute)); // false
console.log("Can read and write?", checkPermission(userPermissions, ReadWrite)); // true
console.log("Has full access?", checkPermission(userPermissions, FullAccess)); // false
console.log("Is admin?", checkPermission(userPermissions, Permission.Admin)); // false

Summary

TypeScript operators are powerful tools that allow you to perform various operations in your code:

  • Arithmetic operators perform mathematical calculations
  • Comparison operators compare values and return boolean results
  • Logical operators combine boolean expressions
  • Assignment operators assign values to variables
  • Type operators (typeof, instanceof, keyof, in) help with type checking and manipulation
  • Bitwise operators manipulate binary representations of numbers
  • String operators concatenate strings
  • Special operators like optional chaining (?.) and nullish coalescing (??) provide safer access to properties

Understanding these operators and when to use them will help you write more efficient, readable, and type-safe TypeScript code.

Exercises

  1. Write a function that takes two numbers and returns their sum, difference, product, and quotient as an object.

  2. Create a function that safely accesses nested properties in a complex object using optional chaining.

  3. Implement a simple permission system using bitwise operators where users can have multiple permission flags.

  4. Write a type-safe function that can extract specific properties from objects using the keyof operator.

  5. Create a function that can determine whether an object is an instance of a specific class and handle it accordingly.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)