TypeScript is a statically typed superset of JavaScript that adds type annotations to catch errors during development, improve code readability, and enhance maintainability. This document provides a comprehensive guide to TypeScript, including installation, core features, syntax, and its use across frameworks and libraries.
- What is TypeScript?
- Installation and Setup
- Core TypeScript Concepts
- TypeScript with Frameworks and Libraries
- TypeScript Configuration (
tsconfig.json
) - Best Practices
- Troubleshooting
- Resources
- Definition: TypeScript is an open-source language developed by Microsoft that extends JavaScript with static types. It compiles to plain JavaScript, compatible with any JavaScript runtime (e.g., browsers, Node.js).
- Benefits:
- Catches type errors during development (e.g., passing a
string
to a function expecting anumber
). - Improves IDE support with autocompletion and refactoring.
- Enhances code documentation through explicit types.
- Catches type errors during development (e.g., passing a
- Use Cases: Backend (Node.js, Express), frontend (React, Angular), serverless (Firebase, AWS Lambda), and more.
- Install Node.js: Required for TypeScript’s runtime (download).
- Install TypeScript Globally:
npm install -g typescript
- Check version:
tsc --version
.
- Check version:
- Initialize a Project:
mkdir typescript-project cd typescript-project npm init -y tsc --init
- Create
tsconfig.json
: Basic configuration for TypeScript:{ "compilerOptions": { "target": "es6", "module": "commonjs", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true }, "include": ["src/**/*"], "exclude": ["node_modules"] }
strict: true
: Enables strict type checking (recommended).outDir
: Output directory for compiled JavaScript.rootDir
: Source directory for TypeScript files.
- Install Development Tools:
npm install --save-dev ts-node nodemon
ts-node
: Runs TypeScript files directly.nodemon
: Auto-restarts server during development.
- Create a Sample File (
src/index.ts
):const message: string = "Hello, TypeScript!"; console.log(message);
- Compile and Run:
Or, with
tsc node dist/index.js
ts-node
:ts-node src/index.ts
Explicitly define variable, parameter, and return types using : type
.
let name: string = "Alice"; // String type
let age: number = 25; // Number type
let isActive: boolean = true; // Boolean type
function greet(name: string): string {
return `Hello, ${name}`;
}
// Error: Type 'number' is not assignable to type 'string'
name = 42; // Caught by TypeScript
- Common Types:
string
,number
,boolean
,any
(avoids type checking),unknown
(safer thanany
),void
,null
,undefined
.- Arrays:
string[]
orArray<string>
. - Objects:
{ key: type }
or interfaces (see below).
Define object shapes for consistent data structures.
interface User {
id: number;
name: string;
email?: string; // Optional property
}
const user: User = {
id: 1,
name: "Bob",
// email is optional
};
// Error: Property 'id' is missing
const invalidUser: User = { name: "Alice" };
TypeScript infers types when not explicitly defined.
let count = 10; // Inferred as number
count = "ten"; // Error: Type 'string' is not assignable to type 'number'
function add(a: number, b: number) {
return a + b; // Inferred as number
}
- Union Types (
|
): Allow multiple types.let id: string | number = 123; id = "ABC"; // Valid id = true; // Error: Type 'boolean' is not assignable
- Intersection Types (
&
): Combine multiple types.interface Person { name: string; } interface Employee { id: number; } type Staff = Person & Employee; const staff: Staff = { name: "Carol", id: 1 };
Create reusable components with flexible types.
function wrap<T>(value: T): T[] {
return [value];
}
const numbers: number[] = wrap<number>(42); // [42]
const strings: string[] = wrap<string>("hello"); // ["hello"]
Override TypeScript’s inferred type when you’re certain of the type.
let data: any = "hello";
let str: string = data as string; // Assert as string
console.log(str.toUpperCase()); // HELLO
Use import
/export
for modular code.
// math.ts
export function add(a: number, b: number): number {
return a + b;
}
// index.ts
import { add } from './math';
console.log(add(2, 3)); // 5
TypeScript enhances type safety across various ecosystems. Below are common frameworks and libraries where TypeScript is widely used.
Build REST APIs with typed routes and middleware.
- Install:
npm install express @types/express
- Example:
import express, { Express, Request, Response } from 'express'; const app: Express = express(); const port: number = parseInt(process.env.PORT || '3000', 10); app.get('/hello', (req: Request, res: Response): void => { res.json({ message: 'Hello, TypeScript!' }); }); app.listen(port, () => console.log(`Server running at http://localhost:${port}`));
Type components, props, and state.
- Install:
npm install @types/react @types/react-dom
- Example:
import React from 'react'; interface Props { title: string; } const Title: React.FC<Props> = ({ title }) => <h1>{title}</h1>;
Type Firestore data and Cloud Functions.
- Install:
npm install firebase firebase-admin firebase-functions
- Example:
import * as functions from 'firebase-functions'; import * as admin from 'firebase-admin'; admin.initializeApp(); interface Data { id: number; value: string; } export const getData = functions.https.onRequest(async (req, res) => { const doc: Data = (await admin.firestore().collection('data').doc('1').get()).data() as Data; res.json(doc); });
- Mongoose (MongoDB):
import mongoose, { Schema } from 'mongoose'; interface User { name: string; age: number; } const UserSchema: Schema<User> = new Schema({ name: String, age: Number }); const UserModel = mongoose.model<User>('User', UserSchema);
- TypeORM (SQL):
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; @Entity() class User { @PrimaryGeneratedColumn() id: number; @Column() name: string; }
- GraphQL (Apollo Server):
import { ApolloServer, gql } from 'apollo-server'; const typeDefs = gql`type User { id: Int! name: String! }`; const resolvers = { Query: { user: (): { id: number; name: string } => ({ id: 1, name: "Alice" }) } };
- Jest:
import { describe, it, expect } from '@jest/globals'; describe('add', () => { it('adds numbers', () => { expect(1 + 2).toBe(3); }); });
Customize TypeScript behavior via tsconfig.json
:
- Key Options:
"strict": true
: Enables strict type checking (e.g.,noImplicitAny
,strictNullChecks
)."target": "es6"
: Compiles to ES6 JavaScript."module": "commonjs"
: For Node.js; use"esnext"
for modern JavaScript."esModuleInterop": true
: Simplifies importing CommonJS modules.
- Example:
{ "compilerOptions": { "target": "es6", "module": "commonjs", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true } }
- Use Explicit Types:
- Prefer
: string
,: number
overany
for clarity:let id: number = 1; // Good let id: any = 1; // Avoid
- Prefer
- Enable Strict Mode:
- Set
"strict": true
intsconfig.json
to catch errors early.
- Set
- Use Interfaces for Objects:
- Define reusable shapes:
interface Config { url: string; port: number; }
- Define reusable shapes:
- Avoid
any
:- Use
unknown
or specific types instead.let value: unknown = JSON.parse(data); if (typeof value === 'string') { /* Safe */ }
- Use
- Leverage Type Inference:
- Omit types where obvious to reduce boilerplate:
let count = 10; // Inferred as number
- Omit types where obvious to reduce boilerplate:
- Use Generics for Flexibility:
function getFirst<T>(arr: T[]): T { return arr[0]; }
- Type External Libraries:
- Install
@types/*
packages (e.g.,npm install @types/express
).
- Install
- Organize Modules:
- Use separate files for types and logic:
// types/user.ts export interface User { id: number; name: string; }
- Use separate files for types and logic:
- Type Errors:
- Run
tsc
to check for errors. - Example:
Type 'string' is not assignable to type 'number'
indicates incorrect type usage.
- Run
- Missing Types:
- Install type definitions:
npm install @types/<library>
. - Example:
npm install @types/node
for Node.js globals.
- Install type definitions:
- Module Resolution:
- Ensure
"esModuleInterop": true
intsconfig.json
for CommonJS modules.
- Ensure
- Runtime Errors:
- TypeScript catches compile-time errors, not runtime. Validate inputs:
const id: number = parseInt(input, 10); if (isNaN(id)) throw new Error('Invalid ID');
- TypeScript catches compile-time errors, not runtime. Validate inputs:
- IDE Support:
- Use VS Code for autocompletion and error highlighting.
- TypeScript Official Documentation
- TypeScript Handbook
- DefinitelyTyped (type definitions)
- TS Node for running TypeScript directly
- TypeScript Playground for experimenting