TypeScript
sources:
- text: Standard textbook reference
This section covers language learning, proficiency levels, and assessment frameworks. These materials support preparation for standardised language examinations and communicative competence development.
TypeScript
Section titled “TypeScript”TypeScript is a statically-typed superset of JavaScript developed and maintained by Microsoft. It adds optional type annotations, interfaces, generics, and other features to JavaScript, enabling developers to catch errors at compile time rather than at runtime. TypeScript compiles to plain JavaScript, meaning it runs anywhere JavaScript runs: in browsers, on servers (Node.js), and in any JavaScript runtime.
TypeScript has become the industry standard for large-scale JavaScript development. Its type system provides documentation through code, enables better tooling (autocompletion, refactoring, navigation), and catches entire categories of bugs before they reach production. Learning TypeScript is essential for any serious JavaScript developer.
Prerequisites: Review the prerequisite topics before attempting this section.
Topics
Section titled “Topics”- Advanced Patterns
- Advanced Types
- Classes
- Enums And Modules
- Error Handling
- Flashcards Typescript Basics
- Functions
- Generics
- Practice Typescript Basics
- Tooling And Configuration
- Types And Annotations
- Typescript With React
- Typescript
Why TypeScript?
Section titled “Why TypeScript?”JavaScript is a dynamically-typed language: variables can hold any type of value, and type errors are only caught when the problematic code executes. This flexibility is powerful for small scripts but becomes a liability in large codebases where:
- A function expecting a number might receive a string, causing subtle bugs that only appear in certain code paths
- Refactoring is risky because the compiler cannot verify that all call sites have been updated
- New team members cannot easily understand what types a function expects or returns
TypeScript solves these problems by adding a type system that is checked at compile time. The benefits include:
- Early error detection, Type errors are caught before the code runs
- Better IDE support, Autocompletion, inline documentation, and refactoring tools work reliably
- Self-documenting code, Type annotations serve as documentation that never goes out of date
- Safer refactoring, The compiler verifies that changes do not break existing code
- Improved collaboration, Types communicate intent clearly between team members
Intuition: What TypeScript Really Is
Section titled “Intuition: What TypeScript Really Is”JavaScript with a safety net: TypeScript does not change how JavaScript works. It adds a layer of checking on top. When you write TypeScript, you are writing JavaScript with additional annotations that tell the compiler what types of values your code expects and produces.
Why it matters: Modern web applications are complex, often involving hundreds of files and thousands of lines of code. Without type safety, small errors can cascade into hard-to-debug issues. TypeScript catches these errors during development, when they are cheap to fix, rather than in production, when they are expensive.
The key insight: TypeScript’s type system is structural, not nominal. Two types are compatible if their structures match, regardless of their names. This means TypeScript types are flexible and duck-typing friendly, while still providing strong safety guarantees.
Types and Annotations
Section titled “Types and Annotations”TypeScript provides several basic types that map to JavaScript’s runtime types:
Primitive Types
Section titled “Primitive Types”TypeScript supports all JavaScript primitive types with dedicated type keywords:
stringText values. Example:let name: string = "Alice";numberAll numeric values (integers and floats). Example:let age: number = 25;booleanTrue or false. Example:let active: boolean = true;nullandundefinedAbsence of value. Example:let x: null = null;bigintArbitrary-precision integers. Example:let big: bigint = 100n;symbolUnique identifiers. Example:let sym: symbol = Symbol("key");
Arrays
Section titled “Arrays”Arrays can be typed using either the element type followed by square brackets or the generic Array syntax:
number[]An array of numbersArray<string>An array of strings (generic syntax)readonly number[]A readonly array that cannot be modified after creation
Readonly arrays are useful for representing immutable data. Methods like push, pop, and splice are not available on readonly arrays, which prevents accidental modification.
Tuples
Section titled “Tuples”Tuples are fixed-length arrays where each position has a specific type. They are useful for representing structured data with a known shape:
[string, number]First element is a string, second is a number[string, number?]Second element is optional[string, ...number[]]A string followed by any number of numbers
Tuples are commonly used as return types for functions that return multiple values, or as elements in data structures where the position of each element carries meaning.
Object Types
Section titled “Object Types”Object types describe the shape of objects by specifying the names and types of their properties:
- Inline object types:
{ name: string; age: number; } - Optional properties:
{ name: string; email?: string; }(the?makes email optional) - Index signatures:
{ [key: string]: number; }(any string key maps to a number) - Readonly properties:
{ readonly id: number; name: string; }
Type Aliases and Interfaces
Section titled “Type Aliases and Interfaces”Both type aliases and interfaces can describe object shapes, but there are key differences:
Type aliases use the type keyword and can represent any type: primitives, unions, intersections, tuples, and objects. They are more flexible but cannot be extended or implemented by classes.
Interfaces use the interface keyword and can only describe object shapes (or function signatures). They support declaration merging (you can declare the same interface multiple times and the declarations merge) and can be extended with extends or implemented by classes with implements.
Rule of thumb: Use interfaces for object shapes that might be implemented by classes. Use type aliases for everything else (unions, intersections, mapped types, tuples).
Union and Intersection Types
Section titled “Union and Intersection Types”Union types (A | B) represent a value that can be one of several types. This is useful for functions that accept different types of input or for variables that can hold different kinds of values.
Intersection types (A & B) combine multiple types into one. The resulting type has all the properties of all the combined types. This is useful for composing object types from smaller pieces.
Literal Types
Section titled “Literal Types”Literal types restrict a variable to a specific set of values. They are extremely useful for representing states, directions, or any domain where only certain values are valid:
- String literals:
"north" | "south" | "east" | "west" - Numeric literals:
1 | 2 | 3 | 4 | 5 | 6 - Boolean literals:
true | false
Literal types combined with discriminated unions enable powerful pattern matching in TypeScript.
Functions
Section titled “Functions”Functions are the building blocks of TypeScript programs. TypeScript’s type system for functions ensures that you call functions with the correct arguments and handle their return values properly.
Function Type Annotations
Section titled “Function Type Annotations”Every function should have type annotations for its parameters and return type. This serves as documentation and enables the compiler to catch errors:
- Parameters: Each parameter gets a type annotation. Example:
(name: string, age: number) - Return type: The type after the colon. Example:
: stringor: void - Optional parameters: Use
?after the parameter name. Example:(name: string, greeting?: string) - Default parameters: Provide a default value. Example:
(greeting: string = "Hello") - Rest parameters: Use
...to accept any number of arguments. Example:(...numbers: number[])
Function Overloads
Section titled “Function Overloads”Function overloads allow a function to have multiple signatures with different parameter types. The implementation must handle all signatures. Overloads are useful when a function’s return type depends on its input type.
Higher-Order Functions
Section titled “Higher-Order Functions”Functions that accept other functions as parameters or return functions are called higher-order functions. TypeScript’s type system makes them type-safe:
- Callback functions:
(callback: (result: string) => void) => void - Functions returning functions:
(x: number) => (y: number) => number
Higher-order functions are fundamental to functional programming and are used extensively in array methods like map, filter, and reduce.
Generics
Section titled “Generics”Generics allow you to write functions, classes, and interfaces that work with any type while preserving type safety. They are like type parameters that you pass to a function or class.
Generic Functions
Section titled “Generic Functions”A generic function accepts a type parameter (conventionally T) that is determined by the caller:
function identity<T>(x: T): T { return x; }Returns whatever type it receivesfunction first<T>(arr: T[]): T | undefined { return arr[0]; }Returns the first element of any array
Generic Constraints
Section titled “Generic Constraints”You can constrain generic types to objects with specific properties using the extends keyword:
function getLength<T extends { length: number }>(x: T): number { return x.length; }Only accepts types with alengthproperty
Generic Classes and Interfaces
Section titled “Generic Classes and Interfaces”Classes and interfaces can also be generic. This is commonly used for data structures:
class Stack<T> { private items: T[] = []; push(item: T): void { ... } }A type-safe stack that works with any typeinterface Repository<T> { findById(id: string): T | null; save(entity: T): void; }A generic interface for data access
Advanced Types
Section titled “Advanced Types”Mapped Types
Section titled “Mapped Types”Mapped types transform existing types by iterating over their properties. TypeScript provides several built-in mapped types:
Partial<T>Makes all properties optionalRequired<T>Makes all properties requiredReadonly<T>Makes all properties readonlyPick<T, K>Extracts a subset of propertiesOmit<T, K>Removes specific properties
Conditional Types
Section titled “Conditional Types”Conditional types create types based on conditions. They use the syntax T extends U ? X : Y, meaning “if T is assignable to U, use X, otherwise use Y.”
Template Literal Types
Section titled “Template Literal Types”Template literal types create string types from patterns. They are useful for type-safe string manipulation:
type EventName = ${"click" | "focus" | "blur"}Creates"click" | "focus" | "blur"type CSSProperty = ${"margin" | "padding"}-${"top" | "bottom" | "left" | "right"}Creates all combinations
Enums define a set of named constants. They are useful for representing a fixed set of choices:
- Numeric enums:
enum Direction { Up, Down, Left, Right }Values auto-increment from 0 - String enums:
enum Color { Red = "red", Green = "green", Blue = "blue" }Explicit string values - Const enums:
const enum Status { Active, Inactive }Inlined at compile time for better performance
Modules and Namespaces
Section titled “Modules and Namespaces”TypeScript uses ES modules as its module system:
exportandimportNamed exports and default exports work as in JavaScriptimport typeImport only the type, erased at compile timenamespaceGroup related declarations (less common in modern TypeScript)
Classes
Section titled “Classes”TypeScript classes extend JavaScript classes with access modifiers, abstract members, and property declarations:
publicAccessible from anywhere (default)privateAccessible only within the classprotectedAccessible within the class and its subclassesreadonlyCan only be assigned in the constructor
Abstract Classes
Section titled “Abstract Classes”Abstract classes cannot be instantiated directly. They serve as base classes that define a common interface and shared implementation for related classes:
abstract class Shape { abstract area(): number; }Declares a required methodclass Circle extends Shape { area() { return Math.PI * this.radius ** 2; } }Implements the abstract method
Property Declarations
Section titled “Property Declarations”TypeScript allows you to declare class properties with their types directly in the constructor parameters using parameter properties:
constructor(public name: string, private age: number) {}Creates and initializes properties automatically
Error Handling
Section titled “Error Handling”TypeScript provides several patterns for handling errors:
try/catch/finallyStandard JavaScript error handling with typed catch parametersResult<T, E>A functional pattern that represents success or failure without exceptions- Discriminated unions, Use union types with a
kindorstatusfield to represent error states in the type system
The key principle is to make error states explicit in the type system rather than relying on runtime checks or exceptions alone.
Tooling and Configuration
Section titled “Tooling and Configuration”tsconfig.json
Section titled “tsconfig.json”The TypeScript configuration file controls how the compiler processes your code. Key options include:
targetThe JavaScript version to emit (ES5, ES2015, ES2020, ESNext)moduleThe module system (CommonJS, ESNext, NodeNext)strictEnables all strict type-checking optionsoutDirThe output directory for compiled filesrootDirThe root directory of source filesincludeandexcludeWhich files to compile
Compiler Options
Section titled “Compiler Options”strict: trueEnables all strict checks (recommended for new projects)noImplicitAnyErrors on variables without explicit typesstrictNullChecksMakes null and undefined distinct typesnoUnusedLocalsErrors on unused local variablesnoUnusedParametersErrors on unused function parametersnoFallthroughCasesInSwitchErrors on fallthrough switch cases
TypeScript with React
Section titled “TypeScript with React”TypeScript and React work together to provide type-safe component development:
- Component props: Define interfaces for props objects
- State: Type the state object and setState calls
- Events: Use React event types like
React.ChangeEvent<HTMLInputElement> - Hooks:
useState<T>anduseRef<T>accept generic type parameters - Context: Type the context value with
React.createContext<T>
Study Tips for TypeScript
Section titled “Study Tips for TypeScript”Start with strict mode, Enable
strict: truein tsconfig.json from the beginning. It catches more errors and teaches you better TypeScript habits.Type as you go, Add types to new code immediately. Do not leave typing for later. Retroactive typing is much harder than writing types from the start.
Use the type inference, TypeScript can often infer types from usage. You do not always need explicit annotations. Let the compiler do the work when the type is obvious.
Learn the utility types,
Partial``Required``Pick``Omit``Record``Exclude``Extractthese save you from writing repetitive type definitions.Read error messages carefully, TypeScript error messages are descriptive and often tell you exactly what is wrong. Learn to parse them.
Use
anyas a last resort,anydisables type checking for a value. It is sometimes necessary during migration, but overuse defeats the purpose of TypeScript.Practise with real projects, The best way to learn TypeScript is to convert an existing JavaScript project or start a new project with TypeScript from the beginning.
Common Mistakes in TypeScript
Section titled “Common Mistakes in TypeScript”Using
anyto silence errors: If you type something asany, you lose all type safety for that value. Instead, useunknownand narrow the type with type guards.Confusing
interfaceandtype: Both can describe object shapes. Interfaces are better for class implementations and declaration merging. Types are better for unions, intersections, and mapped types.Ignoring the
strictNullChecksflag: Without strict null checks,nullandundefinedcan be assigned to any type, which is a major source of runtime errors. Always enable strict null checks.Over-annotating: You do not need to annotate every variable. TypeScript’s type inference is powerful. Only annotate when the inferred type is not specific enough or when the type is not obvious from context.
Not using type narrowing: TypeScript can narrow types through control flow (if statements, typeof checks, instanceof checks). Use this feature to write type-safe code without explicit casts.
Cross-References
Section titled “Cross-References”- Advanced Types: Deep dive into conditional types, mapped types, and template literal types
- Generics: Writing reusable, type-safe code
- Functions: Function types, overloads, and higher-order functions
- Classes: Object-oriented TypeScript with access modifiers and abstract classes
- Error Handling: Patterns for type-safe error handling
- Tooling and Configuration: tsconfig.json and compiler options
Further Reading
Section titled “Further Reading”- Programming TypeScript by Boris Cherny, Comprehensive guide to TypeScript
- Effective TypeScript by Dan Vanderkam, 62 specific ways to improve your TypeScript
- TypeScript official handbook (typescriptlang.org/docs/handbook), The definitive reference
- TypeScript in 50 Lessons by Stefan Baumgartner, Practical TypeScript patterns
Keep practising and reviewing to master this topic.