Skip to content

TypeScript for PHP Developers

A

Al Amin Ahamed

Senior Engineer

10 min read
𝕏 in

I spent eight years writing PHP before I wrote my first serious TypeScript. The mental model transfer is smoother than you'd expect — but there are enough sharp edges that a PHP developer coming to TypeScript fresh will waste time on avoidable mistakes. Here's the translation guide I wish I'd had.

The Basics Are Familiar

PHP's type system:

function greet(string $name, int $age): string { return "Hello {$name}, you are {$age} years old."; }

TypeScript:

function greet(name: string, age: number): string { return `Hello ${name}, you are ${age} years old.`; }

The syntax differs; the intent is identical.

null vs undefined — The Key Gotcha

PHP has null. TypeScript has both null and undefined — and they're different.

  • undefined — variable declared but never assigned
  • null — explicitly assigned "nothing"

In PHP, unset properties throw. In TypeScript, accessing an unset property returns undefined (no error). This burns every PHP developer at least once.

const user = { name: 'Al Amin' }; console.log(user.email); // undefined — no error in JS!

Turn on strictNullChecks in tsconfig.json and TypeScript will catch this at compile time.

Optional Chaining

PHP's null-safe operator: $user?->address?->city

TypeScript's equivalent: user?.address?.city

They're syntactically identical in purpose.

Interfaces vs Types

PHP has interfaces as contracts for classes. TypeScript interfaces shape objects (data):

interface Post { id: number; title: string; publishedAt: Date | null; } // type aliases work too — use interface for objects, type for unions type Status = 'draft' | 'published' | 'archived';

PHP has no equivalent of union types in data (Status above). TypeScript's union types replace the PHP pattern of using string constants.

Generics

PHP:

/** * @template T * @param array<T> $items * @param callable(T): bool $fn * @return array<T> */ function filter(array $items, callable $fn): array { return array_values(array_filter($items, $fn)); }

TypeScript:

function filter<T>(items: T[], fn: (item: T) => boolean): T[] { return items.filter(fn); }

TypeScript generics are first-class. You don't need PHPDoc workarounds.

Async / Await

PHP's synchronous model has no direct equivalent of promises. The closest mental model: think of async/await as Laravel's job queues, but inline in your code.

async function fetchPost(id: number): Promise<Post> { const response = await fetch(`/api/posts/${id}`); return response.json(); } // Calling it const post = await fetchPost(42);

The await pauses execution of the current function until the promise resolves — other code continues running in the meantime. It's non-blocking I/O, not concurrency.

tsconfig.json Essentials

{ "compilerOptions": { "strict": true, "target": "ES2020", "module": "ESNext", "moduleResolution": "bundler", "jsx": "react-jsx", "baseUrl": ".", "paths": { "@/*": ["resources/js/*"] } } }

"strict": true enables all the checks PHP developers expect from a type system. Without it, TypeScript is optional and mostly useless.

Share 𝕏 in
A

Al Amin Ahamed

Senior software engineer & AI practitioner. Building things in Laravel, PHP, and TypeScript.

About me →

One email a month. No noise.

What I shipped, what I read, occasional deep dive. Unsubscribe anytime.