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.
Operator | Description | Example |
---|---|---|
+ | Addition | 5 + 3 equals 8 |
- | Subtraction | 5 - 3 equals 2 |
* | Multiplication | 5 * 3 equals 15 |
/ | Division | 6 / 3 equals 2 |
% | Modulus (remainder) | 5 % 2 equals 1 |
++ | Increment | let x = 5; x++; results in x being 6 |
-- | Decrement | let x = 5; x--; results in x being 4 |
** | Exponentiation | 2 ** 3 equals 8 |
Let's see these in action:
// 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.
Operator | Description | Example |
---|---|---|
== | Equal (value) | 5 == "5" is true |
=== | Strict equal (value and type) | 5 === "5" is false |
!= | Not equal | 5 != "6" is true |
!== | Strict not equal | 5 !== "5" is true |
> | Greater than | 5 > 3 is true |
< | Less than | 5 < 3 is false |
>= | Greater than or equal | 5 >= 5 is true |
<= | Less than or equal | 5 <= 3 is false |
Example:
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.
Operator | Description | Example |
---|---|---|
&& | Logical AND | true && false is false |
|| | Logical OR | true || false is true |
! | Logical NOT | !true is false |
?? | Nullish Coalescing | null ?? "default" is "default" |
Example:
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.
Operator | Description | Example |
---|---|---|
= | Assignment | x = 5 |
+= | Addition assignment | x += 3 same as x = x + 3 |
-= | Subtraction assignment | x -= 3 same as x = x - 3 |
*= | Multiplication assignment | x *= 3 same as x = x * 3 |
/= | Division assignment | x /= 3 same as x = x / 3 |
%= | Modulus assignment | x %= 3 same as x = x % 3 |
**= | Exponentiation assignment | x **= 3 same as x = x ** 3 |
Example:
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.
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:
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.
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.
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.
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.
Operator | Description | Example |
---|---|---|
& | Bitwise AND | 5 & 3 is 1 |
| | Bitwise OR | 5 | 3 is 7 |
^ | Bitwise XOR | 5 ^ 3 is 6 |
~ | Bitwise NOT | ~5 is -6 |
<< | Left shift | 5 << 1 is 10 |
>> | Right shift | 5 >> 1 is 2 |
>>> | Unsigned right shift | 5 >>> 1 is 2 |
Example:
// 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.
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.
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
// 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
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
// 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
-
Write a function that takes two numbers and returns their sum, difference, product, and quotient as an object.
-
Create a function that safely accesses nested properties in a complex object using optional chaining.
-
Implement a simple permission system using bitwise operators where users can have multiple permission flags.
-
Write a type-safe function that can extract specific properties from objects using the
keyof
operator. -
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! :)