Your Next.js project uses TypeScript - it's like JavaScript with superpowers! It adds types that help avoid bugs.
TypeScript is JavaScript with a type system. TypeScript code is compiled to regular JavaScript.
1// JavaScript - no types
2function greet(name) {
3 return "Hello " + name;
4}
5
6greet(123); // Works, but logical error!1// TypeScript - with types
2function greet(name: string) {
3 return "Hello " + name;
4}
5
6greet(123); // ❌ Error: Argument of type 'number' not assignable to 'string'Why TypeScript?
1// String
2const shipName: string = "Black Pearl";
3const captain: string = "Jack Sparrow";
4
5// Number
6const crewCount: number = 42;
7const treasureValue: number = 1000000;
8
9// Boolean
10const isSailing: boolean = true;
11const hasKraken: boolean = false;
12
13// Undefined and Null
14let treasure: number | undefined; // Can be number or undefined
15let kraken: null | object = null;1// Array of numbers
2const levels: number[] = [1, 2, 3, 4, 5];
3
4// Array of strings
5const pirates: string[] = ["Jack", "Anne", "Blackbeard"];
6
7// Alternative syntax
8const ships: Array<string> = ["Pearl", "Dutchman"];
9
10// Mixed array (union type)
11const mixed: (string | number)[] = ["Jack", 42, "Anne", 7];1// Inline type
2const pirate: {
3 name: string;
4 level: number;
5 ship: string;
6} = {
7 name: "Jack Sparrow",
8 level: 10,
9 ship: "Black Pearl"
10};
11
12// Problem: we have to repeat types for every pirate!Interface is like a blueprint for objects - it defines the shape of data.
1interface Pirate {
2 name: string;
3 level: number;
4 ship: string;
5 isActive: boolean;
6}
7
8// Now we can reuse this type multiple times
9const jack: Pirate = {
10 name: "Jack Sparrow",
11 level: 10,
12 ship: "Black Pearl",
13 isActive: true
14};
15
16const anne: Pirate = {
17 name: "Anne Bonny",
18 level: 8,
19 ship: "Revenge",
20 isActive: true
21};
22
23// Array of pirates
24const crew: Pirate[] = [jack, anne];The
? sign means the property is optional:1interface Ship {
2 name: string;
3 captain: string;
4 crewCount: number;
5 treasure?: number; // Optional - can be undefined
6 flag?: string; // Optional
7}
8
9const pearl: Ship = {
10 name: "Black Pearl",
11 captain: "Jack Sparrow",
12 crewCount: 42
13 // treasure and flag are optional - can be omitted
14};
15
16const dutchman: Ship = {
17 name: "Flying Dutchman",
18 captain: "Davy Jones",
19 crewCount: 100,
20 treasure: 1000000 // We have treasure this time
21};1interface GreetFunction {
2 (name: string): string;
3}
4
5const greetPirate: GreetFunction = (name) => {
6 return `Ahoy, ${name}!`;
7};
8
9console.log(greetPirate("Jack")); // "Ahoy, Jack!"TypeScript has two ways to define types:
type and interface.1type Pirate = {
2 name: string;
3 level: number;
4};
5
6type Ship = {
7 name: string;
8 captain: string;
9};1interface Pirate {
2 name: string;
3 level: number;
4}
5
6interface Ship {
7 name: string;
8 captain: string;
9}Differences:
| Feature | Type | Interface | |---------|------|-----------| | Extends | Yes (with
&) | Yes (with extends) |
| Union types | ✅ Yes | ❌ No |
| Primitives | ✅ Yes | ❌ No |
| Re-open | ❌ No | ✅ Yes |When to use:
1// Type can be string OR number
2type ID = string | number;
3
4const userId1: ID = "abc123"; // ✅
5const userId2: ID = 42; // ✅
6
7// Type can be several specific values
8type Status = "pending" | "sailing" | "docked" | "sunk";
9
10const shipStatus: Status = "sailing"; // ✅
11const wrongStatus: Status = "flying"; // ❌ Error!1// Define props types
2interface ButtonProps {
3 text: string;
4 onClick: () => void;
5 variant?: "primary" | "secondary"; // Optional
6}
7
8// Component with typed props
9function Button({ text, onClick, variant = "primary" }: ButtonProps) {
10 return (
11 <button
12 onClick={onClick}
13 className={`btn btn-${variant}`}
14 >
15 {text}
16 </button>
17 );
18}
19
20// Usage
21<Button text="Ahoy!" onClick={() => console.log("Clicked!")} />1interface CardProps {
2 title: string;
3 children: React.ReactNode; // Type for children
4}
5
6function Card({ title, children }: CardProps) {
7 return (
8 <div className="card">
9 <h2>{title}</h2>
10 {children}
11 </div>
12 );
13}
14
15// Usage
16<Card title="Pirate Card">
17 <p>This is content inside card</p>
18</Card>1interface FormProps {
2 onSubmit: (email: string) => void;
3}
4
5function Form({ onSubmit }: FormProps) {
6 const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
7 e.preventDefault();
8 const formData = new FormData(e.currentTarget);
9 const email = formData.get("email") as string;
10 onSubmit(email);
11 };
12
13 return (
14 <form onSubmit={handleSubmit}>
15 <input name="email" type="email" />
16 <button type="submit">Join crew</button>
17 </form>
18 );
19}Generics allow you to create components/functions that work with different types.
1// Generic function
2function getFirstItem<T>(items: T[]): T | undefined {
3 return items[0];
4}
5
6const firstNumber = getFirstItem([1, 2, 3]); // number | undefined
7const firstString = getFirstItem(["a", "b"]); // string | undefined
8
9// Generic interface
10interface Response<T> {
11 data: T;
12 status: number;
13 message: string;
14}
15
16interface Pirate {
17 name: string;
18 level: number;
19}
20
21const pirateResponse: Response<Pirate> = {
22 data: { name: "Jack", level: 10 },
23 status: 200,
24 message: "Success"
25};
26
27const stringResponse: Response<string> = {
28 data: "Hello",
29 status: 200,
30 message: "OK"
31};1// app/pirates/page.tsx
2interface Pirate {
3 id: number;
4 name: string;
5 ship: string;
6 level: number;
7}
8
9export default function PiratesPage() {
10 const pirates: Pirate[] = [
11 { id: 1, name: "Jack Sparrow", ship: "Black Pearl", level: 10 },
12 { id: 2, name: "Anne Bonny", ship: "Revenge", level: 8 }
13 ];
14
15 return (
16 <div>
17 <h1>Pirates</h1>
18 {pirates.map((pirate) => (
19 <div key={pirate.id}>
20 <h2>{pirate.name}</h2>
21 <p>Ship: {pirate.ship}</p>
22 <p>Level: {pirate.level}</p>
23 </div>
24 ))}
25 </div>
26 );
27}1// app/api/pirates/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4interface Pirate {
5 id: number;
6 name: string;
7 level: number;
8}
9
10export async function GET(request: NextRequest) {
11 const pirates: Pirate[] = [
12 { id: 1, name: "Jack Sparrow", level: 10 },
13 { id: 2, name: "Anne Bonny", level: 8 }
14 ];
15
16 return NextResponse.json({ pirates });
17}
18
19export async function POST(request: NextRequest) {
20 const body: Pirate = await request.json();
21
22 // Type validation
23 if (!body.name || typeof body.level !== 'number') {
24 return NextResponse.json(
25 { error: "Invalid data" },
26 { status: 400 }
27 );
28 }
29
30 return NextResponse.json({ success: true, pirate: body });
31}1// app/page.tsx
2import { Metadata } from 'next';
3
4export const metadata: Metadata = {
5 title: "Kraken's Call - Join the Adventure",
6 description: "Epic pirate game built with Next.js",
7 keywords: ["pirate", "game", "adventure"],
8};
9
10export default function HomePage() {
11 return <div>Welcome aboard!</div>;
12}Sometimes you know more about a type than TypeScript does:
1// localStorage returns string | null
2const savedData = localStorage.getItem("pirate");
3
4// We tell TypeScript: "I know this is a string"
5const pirateData = savedData as string;
6
7// Or for JSON
8const pirate = JSON.parse(savedData) as Pirate;
9
10// Type assertion with <>
11const element = document.getElementById("root") as HTMLDivElement;Warning: Use
as carefully - you can fool TypeScript and get a runtime error!TypeScript has built-in utility types:
1interface Pirate {
2 name: string;
3 level: number;
4 ship: string;
5 treasure: number;
6}
7
8// Partial - all properties optional
9type PartialPirate = Partial<Pirate>;
10// { name?: string; level?: number; ship?: string; treasure?: number; }
11
12// Pick - select only certain properties
13type PiratePreview = Pick<Pirate, "name" | "level">;
14// { name: string; level: number; }
15
16// Omit - exclude certain properties
17type PirateWithoutTreasure = Omit<Pirate, "treasure">;
18// { name: string; level: number; ship: string; }
19
20// Required - all properties required
21type RequiredPirate = Required<PartialPirate>;
22// { name: string; level: number; ship: string; treasure: number; }1// any - disables type checking (avoid!)
2let anything: any = "hello";
3anything = 42;
4anything.nonExistent(); // No error! Danger!
5
6// unknown - safer version of any
7let something: unknown = "hello";
8// something.toUpperCase(); // ❌ Error! We must check the type
9
10if (typeof something === "string") {
11 something.toUpperCase(); // ✅ OK!
12}
13
14// never - a type that never occurs
15function throwError(message: string): never {
16 throw new Error(message);
17 // Function never returns a value - always throws an error
18}Your project has a
tsconfig.json file with TypeScript configuration:1{
2 "compilerOptions": {
3 "target": "ES2017", // JS version to compile to
4 "lib": ["dom", "ES2017"], // Available libraries
5 "jsx": "preserve", // Preserve JSX for Next.js
6 "module": "esnext", // Module system
7 "strict": true, // Strict type checking ✅
8 "esModuleInterop": true, // Compatibility with ES modules
9 "skipLibCheck": true, // Speeds up compilation
10 "forceConsistentCasingInFileNames": true
11 }
12}Important options:
strict: true - enables all strict checks (RECOMMENDED!)noImplicitAny: true - doesn't allow any without explicit specificationstrictNullChecks: true - checks if value can be null/undefinedCursor handles TypeScript excellently! Ask AI:
Prompt 1:
1Create an interface for a pirate card with name, level, ship and an array of skillsPrompt 2:
1How to type props for a React component that accepts a title, description and onClick function?Prompt 3:
1Fix TypeScript errors in this code: [paste code]1. Property does not exist
1const pirate = { name: "Jack" };
2console.log(pirate.level); // ❌ Property 'level' does not exist
3
4// Fix: add the property to the interface
5interface Pirate {
6 name: string;
7 level?: number; // Optional
8}2. Type 'X' is not assignable to type 'Y'
1const level: number = "10"; // ❌ string ≠ number
2
3// Fix: convert the type
4const level: number = parseInt("10"); // ✅3. Object is possibly 'undefined'
1const pirates = [{ name: "Jack" }];
2const first = pirates.find(p => p.name === "Jack");
3console.log(first.name); // ❌ first might be undefined!
4
5// Fix: optional chaining
6console.log(first?.name); // ✅
7
8// Or a check
9if (first) {
10 console.log(first.name); // ✅
11}✅ TypeScript - JavaScript with types, more safety ✅ Basic types - string, number, boolean, array ✅ Interface - defining object structure ✅ Type vs Interface - interface for objects, type for union types ✅ Union types - "or" type (
string | number)
✅ Generics - universal types (<T>)
✅ Props typing - interfaces for React components
✅ Utility Types - Partial, Pick, Omit, Required
✅ tsconfig.json - TypeScript configuration
✅ AI helps - Cursor supports TypeScript out-of-the-boxNext steps: In the following modules we'll use TypeScript in every component. You'll learn to type:
See you there! 🚀