PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

TypeScript dla PHP developera – typy, interface, generics, async/await

by Henryk Tews / wtorek, 10 stycznia 2023 / Opublikowano w JavaScript

Jeśli przez lata pisałeś PHP z type hintami i declare(strict_types=1), praca z czystym JavaScriptem boli. Brak typów, brak autouzupełniania, błędy które wychodzą dopiero w przeglądarce. TypeScript rozwiązuje ten problem – dodaje do JavaScriptu system typów który PHP developer natychmiast doceni. Pokazuję podstawy z perspektywy kogoś kto myśli w PHP.

Dlaczego TypeScript, nie czysty JavaScript

PHP developer przyzwyczajony do typed properties, union types i PHPStan będzie czuł się w czystym JS jak bez rąk. TypeScript przynosi to co znamy z PHP 8.x – typy przy zmiennych, parametrach i wartościach zwracanych – ale w ekosystemie JS/Node.js:

// JavaScript - brak typów, błędy w runtime
function calculateTotal(items, taxRate) {
    return items.reduce((sum, item) => sum + item.price * item.qty, 0) * (1 + taxRate);
}

calculateTotal([{price: 10, qty: 2}], 0.23); // ok: 24.6
calculateTotal("oops", 0.23);                 // NaN - żaden błąd przed wykonaniem
calculateTotal([{price: "10", qty: 2}], 0.23); // "1010" - ciche złączenie stringów!
// TypeScript - błędy wykryte przed wykonaniem
interface OrderItem {
    price: number;
    qty: number;
    name: string;
}

function calculateTotal(items: OrderItem[], taxRate: number): number {
    return items.reduce((sum, item) => sum + item.price * item.qty, 0) * (1 + taxRate);
}

calculateTotal([{price: 10, qty: 2, name: 'Widget'}], 0.23); // ok: 24.6
calculateTotal("oops", 0.23);                                  // Error kompilacji!
calculateTotal([{price: "10", qty: 2, name: 'Widget'}], 0.23); // Error kompilacji!

Instalacja i konfiguracja

# Instalacja TypeScript
npm install --save-dev typescript ts-node @types/node

# Inicjalizacja projektu
npx tsc --init

# Uruchomienie pliku TS bez kompilacji (dev)
npx ts-node src/index.ts

# Kompilacja do JS
npx tsc
// tsconfig.json - rekomendowana konfiguracja dla PHP developera
{
    "compilerOptions": {
        "target": "ES2022",
        "module": "commonjs",
        "lib": ["ES2022"],
        "outDir": "./dist",
        "rootDir": "./src",
        "strict": true,           // odpowiednik declare(strict_types=1)
        "noImplicitAny": true,    // brak niejawnego any - jak strict_types
        "strictNullChecks": true, // null i undefined nie są wszędzie
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "exactOptionalPropertyTypes": true
    }
}

Podstawowe typy – analogie z PHP

// Typy podstawowe - odpowiedniki PHP
let name: string = "Jan";          // string
let age: number = 30;              // int|float (JS ma jeden typ numeryczny)
let active: boolean = true;        // bool
let nothing: null = null;          // null
let undef: undefined = undefined;  // nie ma w PHP

// Arrays
let ids: number[] = [1, 2, 3];             // array z PHP
let mixed: (string|number)[] = ['a', 1];   // union type w tablicy

// Tuple - tablica o stałej długości i typach
let pair: [string, number] = ['SKU-001', 29.99];

// Union types - jak PHP 8.0+
let id: string | number = 42;
id = 'abc'; // też ok

// Nullable - jak ?string w PHP
let optionalName: string | null = null;
optionalName = "Anna"; // ok

// Literal types - brak w PHP, TypeScript unikalny
let direction: 'asc' | 'desc' = 'asc';
direction = 'up'; // Error: Type '"up"' is not assignable

Interface i Type – odpowiednik klas i interfejsów PHP

// Interface - jak interface w PHP
interface ProductInterface {
    readonly id: number;
    sku: string;
    name: string;
    price: number;
    isActive: boolean;
    categories: string[];
    description?: string; // opcjonalne - jak ?string w PHP
}

// Type alias - bardziej elastyczny od interface
type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled';

type Money = {
    amount: number;     // w groszach
    currency: string;
};

// Intersection type - jak A&B w PHP 8.1
type AdminUser = ProductInterface & {
    adminLevel: number;
    permissions: string[];
};

// Implementacja interface - jak w PHP
class Product implements ProductInterface {
    readonly id: number;
    sku: string;
    name: string;
    price: number;
    isActive: boolean;
    categories: string[];
    description?: string;

    constructor(data: Omit<ProductInterface, 'id'> & { id?: number }) {
        this.id         = data.id ?? Math.random();
        this.sku        = data.sku;
        this.name       = data.name;
        this.price      = data.price;
        this.isActive   = data.isActive;
        this.categories = data.categories;
        this.description = data.description;
    }

    getFormattedPrice(): string {
        return (this.price / 100).toFixed(2) + ' PLN';
    }
}

Generics – jak szablony typów

// Generics - PHP nie ma odpowiednika (PHPStan templates to closest)
// Ale PHP developer zrozumie ideę z Repository pattern

interface Repository<T, ID = number> {
    findById(id: ID): Promise<T | null>;
    findAll(): Promise<T[]>;
    save(entity: T): Promise<T>;
    delete(id: ID): Promise<boolean>;
}

// Konkretna implementacja - typ T jest podstawiony przy użyciu
class ProductRepository implements Repository<ProductInterface> {
    private items: Map<number, ProductInterface> = new Map();

    async findById(id: number): Promise<ProductInterface | null> {
        return this->items.get(id) ?? null;
    }

    async findAll(): Promise<ProductInterface[]> {
        return Array.from(this.items.values());
    }

    async save(product: ProductInterface): Promise<ProductInterface> {
        this.items.set(product.id, product);
        return product;
    }

    async delete(id: number): Promise<boolean> {
        return this.items.delete(id);
    }
}

// Generic function - działa z dowolnym typem
function first<T>(array: T[]): T | undefined {
    return array[0];
}

const firstProduct = first([{id: 1, sku: 'A', name: 'Widget', price: 100, isActive: true, categories: []}]);
// TypeScript wie że firstProduct jest ProductInterface | undefined

Async/Await – jak w PHP 8.1 Fibers, ale masowo używany

// Async/await - w JS to standard, w PHP dopiero Fibers/ReactPHP
// Dla PHP developera to jak normalne funcje, ale "nieblokujące"

interface ApiResponse {
    items: ProductInterface[];
    total: number;
    page: number;
}

async function fetchProducts(page: number = 1): Promise<ApiResponse> {
    const response = await fetch(`/api/products?page=${page}`);

    if (!response.ok) {
        throw new Error(`API error: ${response.status}`);
    }

    return response.json() as Promise<ApiResponse>;
}

// TypeScript wymusza obsługę Promise - nie możesz "zapomnieć" że to async
async function loadPage(): Promise<void> {
    try {
        const data = await fetchProducts(1);
        console.log(`Załadowano ${data.items.length} z ${data.total} produktów`);
    } catch (error) {
        if (error instanceof Error) {
            console.error(`Błąd: ${error.message}`);
        }
    }
}

TypeScript z Magento 2

Magento 2 używa knockout.js i RequireJS – oba mają definicje typów. Jeśli piszesz własne komponenty JS dla Magento, warto dodać TypeScript do procesu buildowania:

# Typy dla popularnych bibliotek używanych przy Magento
npm install --save-dev @types/knockout @types/requirejs @types/jquery
// Komponent knockout.js z typami TypeScript
import * as ko from 'knockout';

interface CartItem {
    sku: string;
    name: string;
    qty: ko.Observable<number>;
    price: number;
}

class CartViewModel {
    items: ko.ObservableArray<CartItem>;
    total: ko.Computed<number>;

    constructor() {
        this.items = ko.observableArray<CartItem>([]);
        this.total = ko.computed(() =>
            this.items().reduce((sum, item) => sum + item.price * item.qty(), 0)
        );
    }

    addItem(item: CartItem): void {
        this.items.push(item);
    }

    removeItem(item: CartItem): void {
        this.items.remove(item);
    }
}

Podsumowanie

TypeScript dla PHP developera to powrót do domu po długiej wycieczce w dzikie ostępy czystego JS. System typów, interfejsy, union types, strict mode – te koncepty brzmią znajomo bo PHP 8.x poszedł podobną drogą. Kluczowa różnica to generics i asynchroniczność przez Promises – tu TypeScript idzie dalej niż PHP. Jeśli budujesz frontend dla Magento albo piszesz Node.js API – TypeScript to inwestycja która zwraca się przy pierwszym refaktoringu.

About Henryk Tews

Co możesz przeczytać następne

Vue.js dla PHP developera – Options API, Composition API, komunikacja z Magento REST
Next.js dla PHP developera – SSR, Server Components, GraphQL z Magento, porównanie z MVC
React.js – JSX, useState, useEffect, custom hooks, porównanie z Vue
  • Publikacje
  • O autorze
  • Kontakt

© 2026 Created by

GÓRA
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Zawsze aktywne
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Zarządzaj opcjami
  • Zarządzaj serwisami
  • Zarządzaj {vendor_count} dostawcami
  • Przeczytaj więcej o tych celach
Zobacz preferencje
  • {title}
  • {title}
  • {title}