Introduction to TypeScript with AI
Learn TypeScript fundamentals — types, interfaces, generics — with AI-assisted explanations and real-time error fixing.
Why TypeScript matters for AI-assisted development
TypeScript is JavaScript with type annotations. Instead of writing function add(a, b) where a and b could be anything — numbers, strings, objects — you write function add(a: number, b: number): number. This tells both the developer and the computer exactly what the function expects and returns. For AI-assisted development, TypeScript is transformative. When Claude Code reads a TypeScript file, it knows exactly what types each function expects, what shape your data has, and what errors are possible. This means Claude Code gives you more accurate suggestions, catches bugs before you run the code, and writes code that fits your existing patterns. Without types, an AI assistant has to guess. With types, it knows. Start a new project: mkdir ts-playground && cd ts-playground && npm init -y. Install TypeScript: npm install --save-dev typescript @types/node. Create a tsconfig.json: npx tsc --init. This generates a TypeScript configuration file with sensible defaults. Ask Claude Code: Review my tsconfig.json and enable strict mode with the recommended settings for a modern Node.js project. Strict mode enables all of TypeScript's safety checks. Some developers find it annoying at first because it flags more errors — but those errors represent real bugs that JavaScript would silently ignore. Every TypeScript error you fix during development is a runtime crash you prevent in production.
Basic types and type annotations
TypeScript has several basic types. String for text: let name: string = "Alice". Number for all numbers (integers and decimals): let age: number = 30. Boolean for true/false: let active: boolean = true. Arrays: let scores: number[] = [85, 92, 78]. Create a file src/basics.ts and ask Claude Code: Create examples of every TypeScript basic type with comments explaining when to use each one. Include string, number, boolean, array, tuple, enum, any, unknown, void, null, undefined, and never. The key insight: you do not need to annotate everything. TypeScript infers types from context. If you write let count = 0, TypeScript knows count is a number. You only need explicit annotations when TypeScript cannot infer the type — function parameters, complex return types, or variables initialised later. Ask Claude Code: Look at my TypeScript file and remove unnecessary type annotations where TypeScript can infer the type. Also add annotations where they are missing and needed. Run: npx tsc --noEmit. This type-checks your code without producing output files. If you see errors, read them carefully. TypeScript errors are verbose but precise. The error "Type 'string' is not assignable to type 'number'" means exactly what it says — you are trying to put a string where a number is expected. Ask Claude Code: I have TypeScript errors. Explain each one in plain English and fix them. Claude Code excels at this because it can see the full context — not just the error line, but the function that calls it, the data that flows into it, and the types defined elsewhere in your project.
Interfaces and type aliases
Interfaces define the shape of objects. Instead of passing anonymous objects around and hoping they have the right fields, you define a contract. Create src/types.ts: interface User { id: number; name: string; email: string; role: 'admin' | 'user' | 'guest'; createdAt: Date; }. Now any function that expects a User will reject objects missing required fields. Ask Claude Code: Create interfaces for a blog application. I need User, Post, Comment, and Category. Each should have appropriate fields with correct types. Include optional fields where it makes sense. Optional fields use a question mark: interface User { bio?: string; avatarUrl?: string; }. This means bio and avatarUrl can be undefined. Type aliases create custom type names: type UserId = number; type UserRole = 'admin' | 'user' | 'guest'; type UserList = User[]. The difference between interfaces and type aliases is subtle. Interfaces can be extended (interface Admin extends User { permissions: string[] }) and merged (two interface declarations with the same name combine). Type aliases are more flexible with unions and intersections. In practice, use interfaces for object shapes and type aliases for everything else. Ask Claude Code: Convert my existing JavaScript objects to TypeScript interfaces. Look at the data structures in my code and create matching interfaces. This is one of the best ways to learn TypeScript — take working JavaScript and add types to it. Claude Code can do this across an entire project in minutes, giving you a typed codebase that catches errors you never knew existed.
Functions with type safety
Typed functions are where TypeScript shines brightest. A function signature like function calculateDiscount(price: number, discountPercent: number): number tells you everything: it takes two numbers and returns a number. No need to read the implementation to understand the contract. Create src/functions.ts with several examples. Ask Claude Code: Create typed utility functions for a shopping cart. I need calculateSubtotal (takes array of items with price and quantity), applyDiscount (takes subtotal and discount code), calculateTax (takes subtotal and region), and calculateTotal (combines them all). Use proper types for everything. Notice how TypeScript catches errors before you run the code. If you call calculateSubtotal("not an array"), TypeScript flags it immediately. If you forget to handle the case where a discount code is invalid, TypeScript can catch that too with proper return types. Function overloads let you define multiple signatures for the same function. Ask Claude Code: Create a function called formatValue that accepts a number and returns a formatted currency string, or accepts a Date and returns a formatted date string, or accepts a string and returns a trimmed lowercase string. Use TypeScript function overloads. Generic functions work with any type while maintaining type safety. The classic example: function first<T>(arr: T[]): T | undefined { return arr[0]; }. Call first([1, 2, 3]) and TypeScript knows the return type is number | undefined. Call first(["a", "b"]) and it knows the return type is string | undefined. Ask Claude Code: Add generics to my utility functions where it makes sense. Explain why each generic improves type safety. Run: npx tsc --noEmit after each change to verify your types are correct. TypeScript's compiler is your safety net — trust it.
Working with external libraries and type definitions
When you install a JavaScript library, TypeScript does not automatically know its types. Some libraries ship with built-in types (axios, dayjs). Others need separate type packages from the DefinitelyTyped project. Install express: npm install express. You will see a TypeScript error when you import it because express does not ship with types. Install the type definitions: npm install --save-dev @types/express. Now TypeScript knows every type in express — Request, Response, Router, and hundreds more. Ask Claude Code: Check my project's dependencies and install any missing @types packages. Some libraries have excellent types. Others have incomplete or outdated type definitions. When you encounter a library with poor types, you have options. Use type assertions to tell TypeScript you know better: const data = response.body as MyType. Create a declaration file (src/types/library-name.d.ts) with declare module 'library-name' to provide basic types. Or ask Claude Code: The types for this library are incomplete. Create a declaration file that properly types the functions I am using. Run: npx tsc --noEmit and you may see errors from type definitions that conflict with each other. This is common when libraries have peer dependency issues. Ask Claude Code: I am getting TypeScript errors from my node_modules types. Help me resolve the conflicts. Claude Code will identify the conflicting types and suggest fixes — often adding a skipLibCheck: true to tsconfig.json as a pragmatic solution, or pinning specific @types versions. The goal is not perfect types everywhere on day one. The goal is incrementally adding type safety where it catches real bugs. Start with your own code, then gradually type your library usage as you encounter issues.
Migrating JavaScript to TypeScript with AI
The most practical TypeScript skill is migrating existing JavaScript. You do not need to rewrite everything — TypeScript supports gradual adoption. Rename a file from .js to .ts. Run: npx tsc --noEmit. You will likely see dozens of errors. Do not panic. Ask Claude Code: I just renamed this JavaScript file to TypeScript. Fix all the type errors, adding interfaces and type annotations where needed. Keep the logic identical — only add types. Claude Code reads the file, understands the intent of each function, and adds appropriate types. It will create interfaces for the object shapes your code already uses, add parameter and return type annotations to functions, fix any genuine bugs that TypeScript reveals (like accessing properties that might be undefined), and add null checks where your code assumes values exist. For a full project migration, follow this order. First, set up tsconfig.json with allowJs: true and strict: false. This lets TypeScript files and JavaScript files coexist. Second, rename files one at a time, starting with utility files that have no dependencies. Third, fix type errors in each file. Fourth, once all files are .ts, enable strict: true and fix the additional errors it reveals. Ask Claude Code: Create a migration plan for my JavaScript project. List the files in the order I should convert them, starting with the ones that have the fewest dependencies. This bottom-up approach means each file you convert already has typed imports from the files you converted before it. The entire migration for a small project (10 to 20 files) typically takes Claude Code about 15 minutes with your review. For larger projects, budget a file or two per day and the project migrates within a few weeks without disrupting feature development.
AI-Assisted Development
This guide is hands-on and practical. The full curriculum covers the conceptual foundations in depth with structured lessons and quizzes.
Go to lesson