Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

TypeScript dla Next.js - Typy i Interfejsy

Twój projekt Next.js używa TypeScript - to jak JavaScript z supermocami! Dodaje typy, które pomagają unikać błędów.

Czym jest TypeScript? 📘

TypeScript to JavaScript z systemem typów. Kod TypeScript jest kompilowany do zwykłego JavaScript.

1// JavaScript - brak typów
2function greet(name) {
3  return "Hello " + name;
4}
5
6greet(123);  // Działa, ale błąd logiczny!
1// TypeScript - z typami
2function greet(name: string) {
3  return "Hello " + name;
4}
5
6greet(123);  // ❌ Error: Argument of type 'number' not assignable to 'string'

Dlaczego TypeScript?

  • 🛡️ Bezpieczeństwo - błędy wychwytywane przed uruchomieniem
  • 🧠 Intellisense - podpowiedzi w edytorze
  • 📖 Dokumentacja - typy są dokumentacją
  • 🔨 Refactoring - łatwiejsze zmiany w kodzie
  • Używany przez - 95% projektów Next.js

Podstawowe typy w TypeScript

1. Typy prymitywne

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 i Null
14let treasure: number | undefined;  // Może być number lub undefined
15let kraken: null | object = null;

2. Arrays (Tablice)

1// Array liczb
2const levels: number[] = [1, 2, 3, 4, 5];
3
4// Array stringów
5const pirates: string[] = ["Jack", "Anne", "Blackbeard"];
6
7// Alternatywna składnia
8const ships: Array<string> = ["Pearl", "Dutchman"];
9
10// Array mieszany (union type)
11const mixed: (string | number)[] = ["Jack", 42, "Anne", 7];

3. Objects (Obiekty)

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: musimy powtarzać typy dla każdego pirata!

Interfejsy - Definiowanie struktur 🎭

Interface to jak blueprint (plan) dla obiektów - definiuje kształt danych.

Podstawowy interface

1interface Pirate {
2  name: string;
3  level: number;
4  ship: string;
5  isActive: boolean;
6}
7
8// Teraz możemy używać tego typu wielokrotnie
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// Tablica piratów
24const crew: Pirate[] = [jack, anne];

Optional properties (opcjonalne właściwości)

Znak

?
oznacza, że właściwość jest opcjonalna:

1interface Ship {
2  name: string;
3  captain: string;
4  crewCount: number;
5  treasure?: number;  // Opcjonalne - może być undefined
6  flag?: string;      // Opcjonalne
7}
8
9const pearl: Ship = {
10  name: "Black Pearl",
11  captain: "Jack Sparrow",
12  crewCount: 42
13  // treasure i flag są opcjonalne - można pominąć
14};
15
16const dutchman: Ship = {
17  name: "Flying Dutchman",
18  captain: "Davy Jones",
19  crewCount: 100,
20  treasure: 1000000  // Mamy treasure tym razem
21};

Interface dla funkcji

1interface GreetFunction {
2  (name: string): string;
3}
4
5const greetPirate: GreetFunction = (name) => {
6  return `Ahoy, ${name}!`;
7};
8
9console.log(greetPirate("Jack"));  // "Ahoy, Jack!"

Type vs Interface 🤔

TypeScript ma dwa sposoby definiowania typów:

type
i
interface
.

Type

1type Pirate = {
2  name: string;
3  level: number;
4};
5
6type Ship = {
7  name: string;
8  captain: string;
9};

Interface

1interface Pirate {
2  name: string;
3  level: number;
4}
5
6interface Ship {
7  name: string;
8  captain: string;
9}

Różnice:

| Feature | Type | Interface | |---------|------|-----------| | Extends | Tak (z

&
) | Tak (z
extends
) | | Union types | ✅ Tak | ❌ Nie | | Primitives | ✅ Tak | ❌ Nie | | Re-open | ❌ Nie | ✅ Tak |

Kiedy używać:

  • Interface - dla obiektów, React components props
  • Type - dla union types, primitives, złożonych typów

Union types - Typ "lub" 🔀

1// Typ może być string LUB number
2type ID = string | number;
3
4const userId1: ID = "abc123";  // ✅
5const userId2: ID = 42;        // ✅
6
7// Typ może być kilka konkretnych wartości
8type Status = "pending" | "sailing" | "docked" | "sunk";
9
10const shipStatus: Status = "sailing";  // ✅
11const wrongStatus: Status = "flying";  // ❌ Error!

Typy w React Components 🎨

Props interface

1// Definiujemy typy props
2interface ButtonProps {
3  text: string;
4  onClick: () => void;
5  variant?: "primary" | "secondary";  // Opcjonalne
6}
7
8// Komponent z typowanymi 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// Użycie
21<Button text="Ahoj!" onClick={() => console.log("Clicked!")} />

Children prop

1interface CardProps {
2  title: string;
3  children: React.ReactNode;  // Typ dla 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// Użycie
16<Card title="Pirate Card">
17  <p>This is content inside card</p>
18</Card>

Event handlers

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 - Uniwersalne typy 🎁

Generics pozwalają tworzyć komponenty/funkcje działające z różnymi typami.

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};

TypeScript w Next.js - Praktyczne przykłady

Page component

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}

API Route handler

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  // Walidacja typu
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}

Metadata type

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}

Type Assertions (as) 🎭

Czasami wiesz więcej o typie niż TypeScript:

1// localStorage zwraca string | null
2const savedData = localStorage.getItem("pirate");
3
4// Mówimy TypeScript: "wiem, że to string"
5const pirateData = savedData as string;
6
7// Lub dla JSON
8const pirate = JSON.parse(savedData) as Pirate;
9
10// Type assertion z <>
11const element = document.getElementById("root") as HTMLDivElement;

Uwaga: Używaj

as
ostrożnie - możesz oszukać TypeScript i dostać runtime error!

Utility Types - Gotowe narzędzia 🛠️

TypeScript ma wbudowane utility types:

1interface Pirate {
2  name: string;
3  level: number;
4  ship: string;
5  treasure: number;
6}
7
8// Partial - wszystkie właściwości opcjonalne
9type PartialPirate = Partial<Pirate>;
10// { name?: string; level?: number; ship?: string; treasure?: number; }
11
12// Pick - wybierz tylko niektóre właściwości
13type PiratePreview = Pick<Pirate, "name" | "level">;
14// { name: string; level: number; }
15
16// Omit - wyklucz niektóre właściwości
17type PirateWithoutTreasure = Omit<Pirate, "treasure">;
18// { name: string; level: number; ship: string; }
19
20// Required - wszystkie właściwości wymagane
21type RequiredPirate = Required<PartialPirate>;
22// { name: string; level: number; ship: string; treasure: number; }

any vs unknown vs never 🎲

1// any - wyłącza sprawdzanie typów (unikaj!)
2let anything: any = "hello";
3anything = 42;
4anything.nonExistent();  // Żadnego błędu! Danger!
5
6// unknown - bezpieczniejsza wersja any
7let something: unknown = "hello";
8// something.toUpperCase();  // ❌ Error! Musimy sprawdzić typ
9
10if (typeof something === "string") {
11  something.toUpperCase();  // ✅ OK!
12}
13
14// never - typ który nigdy nie występuje
15function throwError(message: string): never {
16  throw new Error(message);
17  // Funkcja nigdy nie zwraca wartości - zawsze rzuca błąd
18}

tsconfig.json - Konfiguracja TypeScript ⚙️

Twój projekt ma plik

tsconfig.json
z konfiguracją TypeScript:

1{
2  "compilerOptions": {
3    "target": "ES2017",           // Wersja JS do której kompilować
4    "lib": ["dom", "ES2017"],     // Dostępne biblioteki
5    "jsx": "preserve",            // Zachowaj JSX dla Next.js
6    "module": "esnext",           // System modułów
7    "strict": true,               // Ścisłe sprawdzanie typów ✅
8    "esModuleInterop": true,      // Kompatybilność z ES modules
9    "skipLibCheck": true,         // Przyspiesza kompilację
10    "forceConsistentCasingInFileNames": true
11  }
12}

Ważne opcje:

  • strict: true
    - włącza wszystkie ścisłe sprawdzenia (ZALECANE!)
  • noImplicitAny: true
    - nie pozwala na
    any
    bez wyraźnego określenia
  • strictNullChecks: true
    - sprawdza czy wartość może być null/undefined

Używanie AI do TypeScript 🤖

Cursor świetnie radzi sobie z TypeScript! Zapytaj AI:

Prompt 1:

1Stwórz interface dla karty pirata z imieniem, poziomem, statkiem i tablicą umiejętności

Prompt 2:

1Jak stypować props dla React component który przyjmuje tytuł, opis i funkcję onClick?

Prompt 3:

1Popraw błędy TypeScript w tym kodzie: [wklej kod]

Debugowanie błędów TypeScript 🐛

Częste błędy:

1. Property does not exist

1const pirate = { name: "Jack" };
2console.log(pirate.level);  // ❌ Property 'level' does not exist
3
4// Fix: dodaj właściwość do interface
5interface Pirate {
6  name: string;
7  level?: number;  // Opcjonalne
8}

2. Type 'X' is not assignable to type 'Y'

1const level: number = "10";  // ❌ string ≠ number
2
3// Fix: konwertuj typ
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 może być undefined!
4
5// Fix: optional chaining
6console.log(first?.name);  // ✅
7
8// Lub sprawdzenie
9if (first) {
10  console.log(first.name);  // ✅
11}

Podsumowanie 🎓

TypeScript - JavaScript z typami, więcej bezpieczeństwa ✅ Typy podstawowe - string, number, boolean, array ✅ Interface - definiowanie struktury obiektów ✅ Type vs Interface - interface dla obiektów, type dla union types ✅ Union types - typ "lub" (

string | number
) ✅ Generics - uniwersalne typy (
<T>
) ✅ Props typing - interfejsy dla React components ✅ Utility Types - Partial, Pick, Omit, Required ✅ tsconfig.json - konfiguracja TypeScript ✅ AI pomaga - Cursor wspiera TypeScript out-of-the-box

Następne kroki: W kolejnych modułach będziemy używać TypeScript w każdym komponencie. Nauczysz się typować:

  • Server Components
  • API routes
  • Database queries
  • Forms
  • Hooks

Do zobaczenia! 🚀

Przejdź do CodeWorlds