
Typescript notes
What is TypeScript?
TypeScript is JavaScript with added type checking. It allows you to define what kind of data (e.g., strings, numbers, objects) your variables, functions, and other code components can handle. TypeScript code is compiled into regular JavaScript, so it runs anywhere JavaScript does (browsers, Node.js, etc.). The main benefits are:
- Catches errors early: Find bugs during development, not in production.
- Better tooling: Autocomplete, refactoring, and code navigation in editors like VS Code.
- Scales well: Makes large projects easier to manage with clear contracts between code parts.
- Works with JavaScript: You can gradually adopt TypeScript in existing JavaScript projects.
Key Things You Need to Know
1. Setting Up TypeScript
To use TypeScript, you need:
-
Node.js installed.
-
TypeScript compiler (
tsc
): Install it globally or locally via npm.npm install -g typescript
-
A
tsconfig.json
file to configure how TypeScript behaves.tsc --init
Example
tsconfig.json
:{ "compilerOptions": { "target": "es6", // Compile to ES6 JavaScript "module": "commonjs", // Module system for Node.js "strict": true, // Enable strict type checking "outDir": "./dist", // Output compiled JS files here "rootDir": "./src" // Source TS files } }
-
Run TypeScript: Write your code in
.ts
files, then compile to JavaScript:tsc
Or use
ts-node
for Node.js to run TypeScript directly:npm install -g ts-node ts-node src/index.ts
2. Basic Types
TypeScript lets you define types for variables, parameters, and return values. This ensures your code only works with the expected data.
Example: A user profile function
// JavaScript (no types, error-prone)
function updateUserProfile(userId, name, age) {
return { userId, name, age };
}
console.log(updateUserProfile("123", "Alice", "30")); // Oops, age is a string, not a number!
// TypeScript (with types, catches errors)
function updateUserProfile(userId: string, name: string, age: number) {
return { userId, name, age };
}
console.log(updateUserProfile("123", "Alice", 30)); // Works
// console.log(updateUserProfile("123", "Alice", "30")); // Error: Argument of type 'string' is not assignable to parameter of type 'number'
Common Basic Types:
string
: For text, e.g.,"hello"
.number
: For numbers, e.g.,42
or3.14
.boolean
: Fortrue
orfalse
.array
: For lists, e.g.,string[]
for["a", "b"]
.any
: Allows any type (use sparingly, defeats TypeScript’s purpose).unknown
: Safer alternative toany
when type is unknown.void
: For functions that return nothing.null
andundefined
: For absence of value.
Example: Array of user names
let usernames: string[] = ["Alice", "Bob"];
usernames.push("Charlie");
// usernames.push(123); // Error: Argument of type 'number' is not assignable to parameter of type 'string'
3. Interfaces and Types
Interfaces and type aliases define the shape of objects, making it clear what properties and types are expected.
Example: A shopping cart
// Define an interface for a product
interface Product {
id: number;
name: string;
price: number;
inStock: boolean;
}
// Use it in a function
function addToCart(product: Product, quantity: number) {
return {
product,
quantity,
totalPrice: product.price * quantity,
};
}
const laptop: Product = {
id: 1,
name: "Laptop",
price: 999.99,
inStock: true,
};
console.log(addToCart(laptop, 2)); // { product: { id: 1, name: "Laptop", ... }, quantity: 2, totalPrice: 1999.98 }
// addToCart({ id: 2, name: "Mouse" }, 1); // Error: Property 'price' is missing
Type vs. Interface:
- Use
interface
for object shapes, especially when you might extend them. - Use
type
for more flexibility, like unions or primitives.
// Type alias
type UserRole = "admin" | "user" | "guest";
// Interface
interface User {
id: string;
role: UserRole;
}
const user: User = { id: "123", role: "admin" };
// const invalidUser: User = { id: "123", role: "manager" }; // Error: "manager" is not assignable to type UserRole
4. Functions and Return Types
You can specify parameter types and return types to ensure functions behave as expected.
Example: Calculate discount
function applyDiscount(price: number, discountPercentage: number): number {
return price * (1 - discountPercentage / 100);
}
console.log(applyDiscount(100, 20)); // 80
// console.log(applyDiscount("100", 20)); // Error: Argument of type 'string' is not assignable to parameter of type 'number'
Optional Parameters:
Use ?
for optional parameters.
function greetUser(name: string, greeting?: string): string {
return `${greeting || "Hello"}, ${name}!`;
}
console.log(greetUser("Alice")); // Hello, Alice!
console.log(greetUser("Bob", "Hi")); // Hi, Bob!
5. Union and Intersection Types
- Union (
|
): Allows a value to be one of multiple types. - Intersection (
&
): Combines multiple types into one.
Example: Union for a status
type OrderStatus = "pending" | "shipped" | "delivered";
function updateOrderStatus(orderId: string, status: OrderStatus) {
console.log(`Order ${orderId} is now ${status}`);
}
updateOrderStatus("123", "shipped"); // Order 123 is now shipped
// updateOrderStatus("123", "cancelled"); // Error: Argument of type '"cancelled"' is not assignable to parameter of type 'OrderStatus'
Example: Intersection for a detailed user
interface BasicUser {
id: string;
name: string;
}
interface EmployeeDetails {
department: string;
employeeId: number;
}
type Employee = BasicUser & EmployeeDetails;
const employee: Employee = {
id: "123",
name: "Alice",
department: "Engineering",
employeeId: 456,
};
6. Generics
Generics let you write reusable code that works with any type while keeping type safety.
Example: A reusable list fetcher
function fetchItems<T>(items: T[]): T[] {
console.log(`Fetched ${items.length} items`);
return items;
}
const numbers = fetchItems<number>([1, 2, 3]); // Fetched 3 items
const products = fetchItems<Product>([
{ id: 1, name: "Laptop", price: 999.99, inStock: true },
{ id: 2, name: "Mouse", price: 29.99, inStock: true },
]); // Fetched 2 items
Real-world use: Generics are common in libraries like React for components or APIs that handle different data types.
7. Type Assertions
Sometimes you know more about a value’s type than TypeScript does. Use assertions to tell TypeScript what type something is.
Example: Working with DOM elements
const button = document.querySelector("#submit-btn") as HTMLButtonElement;
button.disabled = true; // TypeScript knows this is a button, so `disabled` is valid
// Without `as HTMLButtonElement`, TypeScript only knows it’s an `Element | null`
Note: Use assertions carefully to avoid runtime errors.
8. Modules and TypeScript
TypeScript supports ES Modules and CommonJS. You can import/export types and code.
Example: A user service module
// userService.ts
export interface User {
id: string;
name: string;
}
export function getUser(id: string): User {
return { id, name: "User " + id };
}
// main.ts
import { getUser, User } from "./userService";
const user: User = getUser("123");
console.log(user); // { id: "123", name: "User 123" }
9. Working with JavaScript Libraries
TypeScript works with JavaScript libraries via type definition files (@types
). Install them via npm:
npm install @types/node @types/express
Example: Using Express with TypeScript
import express, { Request, Response } from "express";
const app = express();
app.get("/api/users", (req: Request, res: Response) => {
res.json([{ id: "1", name: "Alice" }]);
});
app.listen(3000, () => console.log("Server running on port 3000"));
If a library lacks types, you can use any
or create a basic declaration:
declare module "some-untyped-library";
10. Advanced Features
-
Enums: Define a set of named values.
enum Role { Admin = "ADMIN", User = "USER", } const user: { name: string; role: Role } = { name: "Alice", role: Role.Admin };
-
Type Guards: Narrow down types dynamically.
function isString(value: unknown): value is string { return typeof value === "string"; } function processInput(input: string | number) { if (isString(input)) { console.log(input.toUpperCase()); // TypeScript knows input is a string } else { console.log(input.toFixed(2)); // TypeScript knows input is a number } }
-
Mapped Types: Transform types dynamically.
type ReadOnlyProduct = { readonly [K in keyof Product]: Product[K]; };
11. Common Gotchas
- Strict Mode: Enable
"strict": true
intsconfig.json
for better type safety, but be ready to fix type errors. any
Pitfall: Avoidany
as it bypasses type checking.- Non-null Assertion (
!
): Use!
to tell TypeScript a value isn’tnull
orundefined
, but only when you’re sure.const element = document.querySelector("#id")!; // Assumes element exists
12. Real-World Workflow Tips
- Gradual Adoption: Rename
.js
files to.ts
and fix errors incrementally. - VS Code: Use TypeScript’s IntelliSense for autocompletion and error detection.
- Linting: Combine TypeScript with ESLint for consistent code style.
- Testing: Use
ts-jest
or similar for testing TypeScript code. - Team Collaboration: Define clear interfaces for APIs and shared components to reduce miscommunication.
Example: A Todo App
interface Todo {
id: number;
text: string;
completed: boolean;
}
class TodoApp {
private todos: Todo[] = [];
addTodo(text: string): Todo {
const todo: Todo = { id: this.todos.length + 1, text, completed: false };
this.todos.push(todo);
return todo;
}
toggleTodo(id: number): Todo | undefined {
const todo = this.todos.find((t) => t.id === id);
if (todo) {
todo.completed = !todo.completed;
}
return todo;
}
getTodos(): Todo[] {
return this.todos;
}
}
const app = new TodoApp();
console.log(app.addTodo("Learn TypeScript")); // { id: 1, text: "Learn TypeScript", completed: false }
console.log(app.toggleTodo(1)); // { id: 1, text: "Learn TypeScript", completed: true }
console.log(app.getTodos()); // [{ id: 1, text: "Learn TypeScript", completed: true }]
13. TypeScript in Popular Frameworks
-
React:
import React from "react"; interface Props { title: string; } const Header: React.FC<Props> = ({ title }) => <h1>{title}</h1>; export default Header;
-
Node.js/Express: See the Express example above.
-
Angular: Built with TypeScript by default, using decorators and services.
14. Debugging and Errors
- Check
tsconfig.json
: Ensuretarget
,module
, andstrict
settings match your project. - Read Error Messages: TypeScript errors are detailed (e.g., “Property X is missing in type Y”).
- Use
tsc --watch
: Auto-recompile on file changes. - Debug Compiled JS: If TypeScript compiles but the JS fails, check the output in
outDir
.
15. Resources
- Official Docs: typescriptlang.org
- TypeScript Handbook: Learn core concepts.
- DefinitelyTyped: Find type definitions for JavaScript libraries (
@types/*
). - Playground: Try TypeScript online at typescriptlang.org/play.
Why Use TypeScript as a Technical Lead?
- Scalability: TypeScript shines in large teams and codebases by enforcing clear contracts.
- Refactoring: Types make it safer to rename or restructure code.
- Onboarding: New developers understand the codebase faster with explicit types.
- Fewer Bugs: Studies (e.g., Microsoft’s internal data) show TypeScript reduces bugs by catching type-related errors early.
Actionable Next Steps
- Start Small: Add TypeScript to one module in your project.
- Learn Gradually: Focus on basic types, then interfaces, then generics.
- Enforce Standards: Set up a
tsconfig.json
withstrict
mode and share it with your team. - Integrate Tools: Use TypeScript with your build tools (Webpack, Vite) and CI/CD pipelines.
- Train Your Team: Share simple examples like the ones above to get buy-in.