Hello World & Running
Hello, World
program HelloWorld;
begin
writeln('Hello, World!');
end. console.log("Hello, World!"); TypeScript (like JavaScript) runs a top-level script with no boilerplate. Pascal requires a
program Name; header and an explicit begin...end. block with a trailing period. TypeScript uses console.log for standard output; Pascal uses the built-in writeln procedure. Single-quoted strings are standard Pascal; TypeScript uses double or single quotes interchangeably.Comments
program CommentsDemo;
begin
// Single-line comment (Free Pascal extension)
{ Brace comment — traditional Pascal style }
(* Parenthesis-star comment — also traditional *)
writeln('done');
end. // Single-line comment
/* Multi-line
block comment */
console.log("done"); Pascal offers three comment syntaxes. The brace style (
{ }) is the most traditional; (* *) predates it; // is a Free Pascal extension from C. TypeScript uses the same // and /* */ as JavaScript. TypeScript also supports JSDoc comments (/** */) for IDE tooling and type inference from JavaScript.Compile & Run
{ Compile with Free Pascal compiler:
fpc HelloWorld.pas
./HelloWorld { on Linux/macOS }
HelloWorld.exe { on Windows }
Or use Compiler Explorer (godbolt.org)
with the fpc322 compiler } // Compile and run with tsx (no build step):
// tsx script.ts
//
// Or compile then run:
// tsc script.ts && node script.js
//
// Or use ts-node:
// ts-node script.ts Pascal compiles to a native binary — no runtime required on the target machine. TypeScript compiles to JavaScript, which then runs on Node.js or in a browser. The
tsx tool (used by this site's test runner) runs TypeScript directly without a separate compile step, similar to how Free Pascal's fpc compiles and outputs a binary in one step.Variables & Types
Variable Declaration
program VarDemo;
var
count: Integer;
message: string;
price: Double;
active: Boolean;
begin
count := 10;
message := 'hello';
price := 9.99;
active := True;
writeln(count, ' ', message, ' ', price:0:2, ' ', active);
end. let count: number = 10;
let message: string = "hello";
let price: number = 9.99;
let active: boolean = true;
console.log(count, message, price.toFixed(2), active); Pascal requires all variables to be declared in a
var block before any code runs, with explicit types. TypeScript allows inline declarations anywhere using let (mutable) or const (immutable). Pascal uses := for assignment and = for comparison; TypeScript uses = for assignment and === for strict equality. Pascal's Boolean literals are True/False (capitalised); TypeScript uses lowercase true/false.Type Inference
program TypeInference;
var
count: Integer;
message: string;
temperature: Double;
begin
{ Pascal: every variable needs an explicit type }
count := 42;
message := 'explicit types required';
temperature := 36.6;
writeln(count, ' ', message, ' ', temperature:0:1);
end. const count = 42; // inferred as number
const message = "inferred"; // inferred as string
const temperature = 36.6; // inferred as number
console.log(count, message, temperature.toFixed(1)); TypeScript infers the type from the initialiser when you use
const or let without an explicit annotation. The type is still fixed at compile time — TypeScript is statically typed, not dynamically typed. Pascal has no type inference; every variable requires an explicit type annotation in the var block. Prefer const over let in TypeScript when the value will not be reassigned.Constants
program ConstantsDemo;
const
MaxItems = 100;
Version = '3.2.2';
Gravity = 9.81;
begin
writeln(MaxItems);
writeln(Version);
writeln(Gravity:0:2);
end. const MAX_ITEMS = 100; // inferred as literal type 100
const VERSION = "6.0";
const GRAVITY = 9.81;
console.log(MAX_ITEMS);
console.log(VERSION);
console.log(GRAVITY.toFixed(2)); Pascal groups constants in a
const block before the main body; they are untyped and the compiler infers their type from the value. TypeScript's const keyword declares an immutable binding — the compiler infers a narrow literal type (100 rather than number). Both are truly immutable: any reassignment is a compile-time error.Number Types
program NumberTypes;
var
small: ShortInt; { -128..127 }
medium: Integer; { 32-bit signed }
large: Int64; { 64-bit signed }
fraction: Double; { 64-bit float }
begin
small := 127;
medium := 2147483647;
large := 9007199254740992;
fraction := 3.14159;
writeln(small);
writeln(medium);
writeln(large);
writeln(fraction:0:5);
end. const small: number = 127;
const medium: number = 2_147_483_647;
// TypeScript has a single 'number' type (64-bit float)
const large: number = 9_007_199_254_740_992; // MAX_SAFE_INTEGER
const fraction: number = 3.14159;
console.log(small, medium, large, fraction.toFixed(5));
// For true 64-bit integers use BigInt:
const hugeInt = 9_223_372_036_854_775_807n;
console.log(hugeInt); Pascal provides fixed-width integer types (
ShortInt, Integer, Int64, Cardinal). TypeScript has a single number type (IEEE 754 double-precision float), which can represent integers exactly only up to 253−1. For integers larger than that, TypeScript offers BigInt (suffixed with n). There is no overflow checking in either language's default integer arithmetic.Boolean
program BooleanDemo;
var
active: Boolean;
hasValue: Boolean;
begin
active := True;
hasValue := False;
writeln(active);
writeln(not active);
writeln(active and hasValue);
writeln(active or hasValue);
end. const active: boolean = true;
const hasValue: boolean = false;
console.log(active);
console.log(!active);
console.log(active && hasValue);
console.log(active || hasValue); Pascal booleans are
True/False (printed as TRUE/FALSE) and use English words for operators: and, or, not, xor. TypeScript uses lowercase true/false and C-style operators: &&, ||, !. TypeScript's && and || short-circuit; Pascal's and/or do not by default (use and then/or else in Free Pascal for short-circuit evaluation).Type Conversion
program TypeConversion;
uses SysUtils;
var
number: Integer;
text: string;
value: Double;
begin
number := 42;
text := IntToStr(number);
writeln(text + ' items');
writeln(StrToInt('99') * 2);
value := 3.14;
writeln(Trunc(value));
end. const number = 42;
const text = String(number); // or number.toString()
console.log(text + " items");
console.log(Number("99") * 2); // or parseInt / parseFloat
const value = 3.14;
console.log(Math.trunc(value)); // truncate toward zero Pascal uses conversion functions from
SysUtils: IntToStr, StrToInt, Trunc. TypeScript provides global functions (Number(), String(), parseInt(), parseFloat()) and Math.trunc(). TypeScript will also coerce values implicitly in some contexts (e.g. string concatenation with + converts the number automatically), unlike Pascal which always requires explicit conversion.Strings
Concatenation & Interpolation
program StringDemo;
uses SysUtils;
var
name: string;
age: Integer;
begin
name := 'Alice';
age := 30;
writeln(name + ' is ' + IntToStr(age) + ' years old');
writeln(Format('%s is %d years old', [name, age]));
end. const name = "Alice";
const age = 30;
console.log(name + " is " + age + " years old"); // concatenation
console.log(`${name} is ${age} years old`); // template literal Pascal uses
+ for concatenation but requires explicit numeric-to-string conversion (IntToStr). TypeScript's + automatically converts numbers when one operand is a string. TypeScript also supports template literals (backtick strings) with ${expression} interpolation — much more readable than Pascal's Format function for mixed-type strings.String Methods
program StringMethods;
uses SysUtils;
var
text: string;
begin
text := ' Hello, World! ';
writeln(Trim(text));
writeln(UpperCase(text));
writeln(LowerCase(text));
writeln(Length(Trim(text)));
writeln(Pos('World', text) > 0);
end. const text = " Hello, World! ";
console.log(text.trim());
console.log(text.toUpperCase());
console.log(text.toLowerCase());
console.log(text.trim().length);
console.log(text.includes("World")); Pascal string functions are free-standing procedures from
SysUtils (Trim(s), UpperCase(s)); TypeScript strings are objects with methods called via dot notation (s.trim(), s.toUpperCase()). TypeScript strings are immutable — all methods return new strings. Pascal strings can be mutated in place using Insert, Delete, and direct character assignment.Search & Slice
program StringSearch;
var
text: string;
position: Integer;
begin
text := 'Hello, World!';
position := Pos('World', text);
writeln(position); { 8 — 1-indexed }
writeln(position > 0); { TRUE if found }
writeln(Copy(text, 1, 5)); { 'Hello' }
writeln(Copy(text, 8, 6)); { 'World!' }
end. const text = "Hello, World!";
const position = text.indexOf("World");
console.log(position); // 7 — 0-indexed
console.log(position >= 0); // true if found
console.log(text.includes("World")); // true — cleaner check
console.log(text.slice(0, 5)); // "Hello"
console.log(text.slice(7)); // "World!" Pascal's
Pos returns a 1-based position (0 if not found); TypeScript's indexOf returns a 0-based position (-1 if not found). Pascal's Copy(str, start, length) uses 1-based indexing; TypeScript's slice(start, end) uses 0-based indices with an optional end (exclusive). TypeScript's includes is cleaner than checking indexOf >= 0 for simple membership tests.Split & Join
{$H+}
program StringSplit;
uses SysUtils, StrUtils, Types;
var
sentence: string;
words: TStringDynArray;
index: Integer;
begin
sentence := 'one two three';
words := SplitString(sentence, ' ');
for index := 0 to Length(words) - 1 do
writeln(words[index]);
writeln(words[0] + '-' + words[1] + '-' + words[2]);
end. const sentence = "one two three";
const words = sentence.split(" ");
words.forEach(word => console.log(word));
console.log(words.join("-")); Pascal's
SplitString (from StrUtils) returns a zero-indexed TStringDynArray. TypeScript's split returns a native string[] that integrates directly with array methods. TypeScript's join re-combines the array with a separator — Pascal requires a manual loop for the equivalent.Arrays & Collections
Array Literals
program ArrayDemo;
var
numbers: array[1..5] of Integer;
index: Integer;
begin
numbers[1] := 10;
numbers[2] := 20;
numbers[3] := 30;
numbers[4] := 40;
numbers[5] := 50;
writeln(Length(numbers));
writeln(numbers[3]);
for index := 1 to Length(numbers) do
writeln(numbers[index]);
end. const numbers: number[] = [10, 20, 30, 40, 50];
console.log(numbers.length);
console.log(numbers[2]); // 0-indexed
for (const number of numbers)
console.log(number); Pascal fixed arrays use a 1-based index by default (
array[1..5]), declared and assigned separately. TypeScript arrays are always 0-based, and can be declared and initialised with an array literal in one line. TypeScript arrays are objects with rich methods (push, pop, map, filter, reduce); Pascal arrays are plain memory regions with no methods.Dynamic Arrays
program DynamicArray;
var
items: array of string;
begin
SetLength(items, 3);
items[0] := 'first';
items[1] := 'second';
items[2] := 'third';
SetLength(items, 4);
items[3] := 'fourth';
writeln(Length(items));
writeln(items[2]);
end. const items: string[] = ["first", "second", "third"];
items.push("fourth");
console.log(items.length);
console.log(items[2]);
items.pop();
console.log(items.length); Pascal's dynamic array (
array of T) is resized with SetLength. TypeScript arrays grow automatically with push, pop, shift, unshift, and splice. There is no SetLength equivalent — the array manages its own memory. TypeScript arrays are backed by JavaScript's dynamic array model, not a fixed-size block of typed memory.Array Methods
program ArrayMethods;
var
numbers: array[1..5] of Integer;
total: Integer;
largest: Integer;
index: Integer;
begin
numbers[1] := 3; numbers[2] := 1; numbers[3] := 4;
numbers[4] := 1; numbers[5] := 5;
total := 0;
largest := numbers[1];
for index := 1 to 5 do begin
total := total + numbers[index];
if numbers[index] > largest then
largest := numbers[index];
end;
writeln('Sum: ', total);
writeln('Max: ', largest);
end. const numbers = [3, 1, 4, 1, 5];
const total = numbers.reduce((sum, n) => sum + n, 0);
const largest = Math.max(...numbers);
console.log("Sum:", total);
console.log("Max:", largest);
console.log("Sorted:", [...numbers].sort((a, b) => a - b)); TypeScript arrays have built-in functional methods —
reduce, map, filter, find, some, every — that replace manual loops. Pascal has none of these; every aggregation requires an explicit loop. The spread operator (...) in TypeScript copies an array before sorting, since sort mutates in place.Tuples
program TupleDemo;
type
TCoordinate = record
X: Double;
Y: Double;
end;
var
origin: TCoordinate;
point: TCoordinate;
begin
origin.X := 0.0; origin.Y := 0.0;
point.X := 3.0; point.Y := 4.0;
writeln(origin.X:0:1, ', ', origin.Y:0:1);
writeln(point.X:0:1, ', ', point.Y:0:1);
end. const origin: [number, number] = [0.0, 0.0];
const point: [number, number] = [3.0, 4.0];
console.log(origin);
console.log(point);
// Named tuple elements (TypeScript 4+):
type Coordinate = [x: number, y: number];
const named: Coordinate = [3.0, 4.0];
console.log(named[0], named[1]); Pascal uses records to group heterogeneous data. TypeScript has native tuple types: fixed-length arrays where each position has a specific type. TypeScript 4 added named tuple elements (
[x: number, y: number]) for documentation purposes. Tuples are useful for multiple return values — a pattern that in Pascal requires either a record or var parameters.Map (Key-Value)
program MapDemo;
type
TEntry = record
key: string;
value: Integer;
end;
var
scores: array[1..3] of TEntry;
index: Integer;
begin
scores[1].key := 'Alice'; scores[1].value := 95;
scores[2].key := 'Bob'; scores[2].value := 87;
scores[3].key := 'Carol'; scores[3].value := 92;
for index := 1 to 3 do
writeln(scores[index].key, ': ', scores[index].value);
end. const scores = new Map<string, number>([
["Alice", 95],
["Bob", 87],
["Carol", 92],
]);
console.log(scores.get("Alice")); // 95
scores.set("Dave", 78);
for (const [name, score] of scores)
console.log(`${name}: ${score}`); Standard Pascal has no built-in key-value map. TypeScript's
Map<K, V> provides O(1) lookups, iteration in insertion order, and a clean API. Plain TypeScript objects ({ Alice: 95, Bob: 87 }) also serve as key-value stores for string keys. Map is preferred when keys are not known at compile time or when iteration order matters.Control Flow
If / Else
program IfElse;
var
score: Integer;
begin
score := 85;
if score >= 90 then
writeln('A')
else if score >= 80 then
writeln('B')
else if score >= 70 then
writeln('C')
else
writeln('Below C');
end. const score = 85;
if (score >= 90)
console.log("A");
else if (score >= 80)
console.log("B");
else if (score >= 70)
console.log("C");
else
console.log("Below C"); The if/else structure is nearly identical. Pascal requires
then after the condition; TypeScript requires parentheses around the condition and uses curly braces for multi-statement bodies. Pascal places a semicolon before else only in specific cases — a common source of Pascal syntax errors. TypeScript's optional braces follow the same rules as C.Case / Switch
program CaseDemo;
var
dayNumber: Integer;
begin
dayNumber := 3;
case dayNumber of
1: writeln('Monday');
2: writeln('Tuesday');
3: writeln('Wednesday');
4, 5: writeln('Thursday or Friday');
6, 7: writeln('Weekend');
else writeln('Unknown');
end;
end. const dayNumber = 3;
switch (dayNumber) {
case 1: console.log("Monday"); break;
case 2: console.log("Tuesday"); break;
case 3: console.log("Wednesday"); break;
case 4:
case 5: console.log("Thursday or Friday"); break;
case 6:
case 7: console.log("Weekend"); break;
default: console.log("Unknown");
} Pascal's
case...of never falls through between branches. TypeScript's switch does fall through unless you add break — a common source of bugs. Multiple values share a branch in Pascal with comma syntax (4, 5:); TypeScript uses stacked case labels with fall-through. For a more Pascal-like no-fall-through construct, TypeScript developers often use if/else chains or object lookups instead.Ternary / Conditional Expression
program TernaryDemo;
var
score: Integer;
result: string;
begin
score := 75;
if score >= 60 then
result := 'pass'
else
result := 'fail';
writeln(result);
end. const score = 75;
const result = score >= 60 ? "pass" : "fail";
console.log(result); Pascal has no ternary expression — an if/else statement must be used to conditionally assign a variable. TypeScript inherits JavaScript's
condition ? thenValue : elseValue ternary operator, which is an expression that can appear anywhere a value is expected. For more complex conditions TypeScript also has the nullish coalescing operator (value ?? default), which Pascal has no equivalent for.Loops
Numeric For Loop
program ForLoops;
var
counter: Integer;
begin
for counter := 1 to 5 do
writeln(counter);
for counter := 5 downto 1 do
writeln(counter);
end. for (let counter = 1; counter <= 5; counter++)
console.log(counter);
for (let counter = 5; counter >= 1; counter--)
console.log(counter); Pascal's
for counter := 1 to 5 do is always step-by-1; downto is step-by-(-1). There is no variable step size. TypeScript's C-style for loop is more flexible: any initialiser, condition, and increment are valid. TypeScript also provides for...of for iterating values and for...in for iterating keys.For-Each / For-Of
program ForeachDemo;
var
fruits: array[1..4] of string;
index: Integer;
begin
fruits[1] := 'apple';
fruits[2] := 'banana';
fruits[3] := 'cherry';
fruits[4] := 'date';
{ Pascal has no foreach; use an indexed for loop }
for index := 1 to Length(fruits) do
writeln(fruits[index]);
end. const fruits = ["apple", "banana", "cherry", "date"];
for (const fruit of fruits)
console.log(fruit);
// With index using entries():
for (const [index, fruit] of fruits.entries())
console.log(`${index + 1}: ${fruit}`); Pascal has no foreach construct — iterating a collection always uses a numeric
for loop with an explicit index variable. TypeScript's for...of iterates over the values of any iterable (arrays, strings, Sets, Maps, generators) without needing an index. Array.entries() provides both the index and value when you need both.While & Repeat-Until
program WhileRepeat;
var
count: Integer;
begin
count := 1;
while count <= 3 do begin
writeln('while: ', count);
Inc(count);
end;
count := 0;
repeat
Inc(count);
writeln('repeat: ', count);
until count >= 3;
end. let count = 1;
while (count <= 3) {
console.log("while:", count);
count++;
}
count = 0;
do {
count++;
console.log("do-while:", count);
} while (count < 3); Pascal's
while maps directly to TypeScript's while. Pascal's repeat...until condition (exit when true) maps to TypeScript's do...while (condition) (exit when false) — the exit condition is the logical inverse. Pascal's built-in Inc(count) procedure increments a variable; TypeScript uses the count++ or count += 1 operators.Functions & Procedures
Procedure (Void Function)
program ProcedureDemo;
procedure Greet(name: string);
begin
writeln('Hello, ', name, '!');
end;
procedure PrintSeparator(character: Char; count: Integer);
var
index: Integer;
begin
for index := 1 to count do
write(character);
writeln;
end;
begin
Greet('World');
PrintSeparator('-', 20);
Greet('Pascal');
end. function greet(name: string): void {
console.log(`Hello, ${name}!`);
}
function printSeparator(character: string, count: number): void {
console.log(character.repeat(count));
}
greet("World");
printSeparator("-", 20);
greet("TypeScript"); Pascal distinguishes procedures (no return value) from functions (with a return value) as separate keywords. TypeScript uses a single
function keyword and marks no-return-value functions with the void return type. The : void annotation is optional but recommended in TypeScript for clarity. TypeScript's string.repeat(n) replaces Pascal's manual character-printing loop.Function (Return Value)
program FunctionDemo;
uses SysUtils;
function Square(number: Integer): Integer;
begin
Result := number * number;
end;
function Greet(name: string): string;
begin
Result := 'Hello, ' + name + '!';
end;
begin
writeln(Square(7));
writeln(Greet('World'));
writeln(Square(Square(2)));
end. function square(number: number): number {
return number * number;
}
function greet(name: string): string {
return `Hello, ${name}!`;
}
console.log(square(7));
console.log(greet("World"));
console.log(square(square(2))); Pascal functions use
Result := value to set the return value; the function body can contain any number of assignments to Result before returning. TypeScript uses return value which exits the function immediately. Both languages require the return type to be declared in the function signature.Arrow Functions / Lambdas
program FunctionTypes;
type
TIntOp = function(value: Integer): Integer;
function Double(value: Integer): Integer;
begin
Result := value * 2;
end;
function ApplyTwice(operation: TIntOp; value: Integer): Integer;
begin
Result := operation(operation(value));
end;
begin
writeln(ApplyTwice(@Double, 3)); { 12 }
end. const double = (value: number): number => value * 2;
const square = (value: number): number => value * value;
function applyTwice(operation: (n: number) => number, value: number) {
return operation(operation(value));
}
console.log(applyTwice(double, 3)); // 12
console.log(applyTwice(square, 3)); // 81 Pascal supports passing functions as values using typed function pointers, but they must be named functions referenced with the
@ operator. TypeScript arrow functions ((param) => expression) define anonymous functions inline. TypeScript arrow functions are also closures — they capture variables from the surrounding scope. Function types in TypeScript are written as (param: Type) => ReturnType.Default & Optional Parameters
program DefaultParams;
procedure Log(message: string; prefix: string = 'INFO');
begin
writeln('[' + prefix + '] ' + message);
end;
begin
Log('Server started');
Log('Something failed', 'ERROR');
end. function log(message: string, prefix = "INFO"): void {
console.log(`[${prefix}] ${message}`);
}
// Optional parameter (may be omitted):
function greet(name: string, greeting?: string): string {
return `${greeting ?? "Hello"}, ${name}!`;
}
log("Server started");
log("Something failed", "ERROR");
console.log(greet("Alice"));
console.log(greet("Bob", "Good day")); Both languages support default parameter values with identical syntax. TypeScript additionally has optional parameters marked with
? — they can be omitted entirely and arrive as undefined inside the function. The nullish coalescing operator (??) provides a default for undefined or null values. Pascal has no optional parameters; every parameter must be supplied.Rest / Variadic Parameters
program VariadicDemo;
uses SysUtils;
{ Pascal has no built-in variadic parameter support.
The closest is an open array parameter: }
function SumAll(const values: array of Integer): Integer;
var
index: Integer;
begin
Result := 0;
for index := 0 to Length(values) - 1 do
Result := Result + values[index];
end;
begin
writeln(SumAll([1, 2, 3]));
writeln(SumAll([10, 20, 30, 40]));
end. function sumAll(...values: number[]): number {
return values.reduce((total, value) => total + value, 0);
}
console.log(sumAll(1, 2, 3)); // 6
console.log(sumAll(10, 20, 30, 40)); // 100 Pascal's open array parameter (
const values: array of T) accepts an array of any size and is the closest equivalent to variadic parameters — but callers must pass an explicit array literal. TypeScript's rest parameter (...values: T[]) lets callers pass any number of individual arguments, which are collected into an array inside the function.Classes & OOP
Class Definition
program ClassDemo;
type
TAnimal = class
private
FName: string;
public
constructor Create(aName: string);
function Speak: string;
property Name: string read FName;
end;
constructor TAnimal.Create(aName: string);
begin
FName := aName;
end;
function TAnimal.Speak: string;
begin
Result := FName + ' makes a sound';
end;
var
animal: TAnimal;
begin
animal := TAnimal.Create('Dog');
writeln(animal.Speak);
writeln(animal.Name);
animal.Free;
end. class Animal {
readonly name: string;
constructor(name: string) {
this.name = name;
}
speak(): string {
return `${this.name} makes a sound`;
}
}
const animal = new Animal("Dog");
console.log(animal.speak());
console.log(animal.name); Pascal class bodies separate declaration (in the
type block) from implementation (method bodies written below). TypeScript classes are self-contained. Pascal requires manual Free to destroy objects; TypeScript uses garbage collection. Pascal private fields use the F prefix by convention (FName); TypeScript uses the private keyword or the #name private field syntax.Inheritance
program InheritanceDemo;
type
TShape = class
public
function Area: Double; virtual; abstract;
procedure Describe;
end;
TCircle = class(TShape)
private
FRadius: Double;
public
constructor Create(radius: Double);
function Area: Double; override;
end;
procedure TShape.Describe;
begin
writeln('Area = ', Area:0:4);
end;
constructor TCircle.Create(radius: Double);
begin
FRadius := radius;
end;
function TCircle.Area: Double;
begin
Result := 3.14159265 * FRadius * FRadius;
end;
var
circle: TCircle;
begin
circle := TCircle.Create(5.0);
circle.Describe;
circle.Free;
end. abstract class Shape {
abstract area(): number;
describe(): void {
console.log(`Area = ${this.area().toFixed(4)}`);
}
}
class Circle extends Shape {
constructor(private radius: number) { super(); }
area(): number { return Math.PI * this.radius ** 2; }
}
const circle = new Circle(5.0);
circle.describe(); Inheritance syntax differs in key ways. Pascal uses
class(ParentClass) for the base class and the virtual; abstract; directive pair; overrides require override. TypeScript uses extends, the abstract keyword on both the class and the method, and override is optional (recommended with noImplicitOverride). TypeScript's constructor parameter shorthand (private radius: number) declares and assigns the field in one step.Access Modifiers
program AccessDemo;
type
TBankAccount = class
private
FBalance: Double;
protected
procedure SetBalance(amount: Double);
public
constructor Create(initialBalance: Double);
function GetBalance: Double;
procedure Deposit(amount: Double);
end;
constructor TBankAccount.Create(initialBalance: Double);
begin
FBalance := initialBalance;
end;
procedure TBankAccount.SetBalance(amount: Double);
begin
FBalance := amount;
end;
function TBankAccount.GetBalance: Double;
begin
Result := FBalance;
end;
procedure TBankAccount.Deposit(amount: Double);
begin
FBalance := FBalance + amount;
end;
var
account: TBankAccount;
begin
account := TBankAccount.Create(1000.0);
account.Deposit(250.0);
writeln(account.GetBalance:0:2);
account.Free;
end. class BankAccount {
private balance: number;
constructor(initialBalance: number) {
this.balance = initialBalance;
}
protected setBalance(amount: number): void {
this.balance = amount;
}
getBalance(): number { return this.balance; }
deposit(amount: number): void { this.balance += amount; }
}
const account = new BankAccount(1000);
account.deposit(250);
console.log(account.getBalance().toFixed(2)); Both languages have
private, protected, and public access modifiers with identical semantics. Pascal access modifiers are section headers inside the class declaration (private followed by members); TypeScript uses per-member keywords. TypeScript also has readonly and #field (truly private at runtime, unlike private which is only a compile-time check).Interfaces & Type Aliases
Interface
program InterfaceDemo;
type
IGreeter = interface
function Greet(name: string): string;
procedure SetLanguage(lang: string);
end;
TEnglishGreeter = class(TInterfacedObject, IGreeter)
public
function Greet(name: string): string;
procedure SetLanguage(lang: string);
end;
function TEnglishGreeter.Greet(name: string): string;
begin
Result := 'Hello, ' + name + '!';
end;
procedure TEnglishGreeter.SetLanguage(lang: string);
begin
writeln('Language set to: ', lang);
end;
var
greeter: IGreeter;
begin
greeter := TEnglishGreeter.Create;
writeln(greeter.Greet('Alice'));
greeter.SetLanguage('English');
end. interface Greeter {
greet(name: string): string;
setLanguage(lang: string): void;
}
class EnglishGreeter implements Greeter {
greet(name: string): string {
return `Hello, ${name}!`;
}
setLanguage(lang: string): void {
console.log(`Language set to: ${lang}`);
}
}
const greeter: Greeter = new EnglishGreeter();
console.log(greeter.greet("Alice"));
greeter.setLanguage("English"); Interfaces work similarly in both languages. Pascal requires class implementations to inherit from
TInterfacedObject; TypeScript uses the implements keyword. A key difference: TypeScript interfaces support structural typing — any object with the required shape satisfies the interface, even without an explicit implements declaration. Pascal uses nominal typing — the explicit declaration is required.Type Aliases & Object Types
program TypeAliasDemo;
type
Score = Integer; { type alias }
TPoint = record { structured type }
X, Y: Double;
end;
TName = string;
var
points: Score;
location: TPoint;
firstName: TName;
begin
points := 95;
location.X := 3.0; location.Y := 4.0;
firstName := 'Alice';
writeln(points);
writeln(location.X:0:1, ', ', location.Y:0:1);
writeln(firstName);
end. type Score = number; // type alias
type Name = string; // type alias
type Point = { x: number; y: number }; // object type alias
const points: Score = 95;
const location: Point = { x: 3.0, y: 4.0 };
const firstName: Name = "Alice";
console.log(points);
console.log(`${location.x}, ${location.y}`);
console.log(firstName); Pascal's
type block creates named type aliases and new structured types (record). TypeScript's type keyword creates aliases for any type — primitives, objects, unions, intersections, or tuples. TypeScript object types ({ x: number; y: number }) are structurally typed: any object with those properties satisfies the type, regardless of how it was created.Union Types
program UnionDemo;
type
{ Pascal uses variant records for discriminated unions }
TValueKind = (VKInteger, VKString, VKBoolean);
TValue = record
Kind: TValueKind;
IntVal: Integer;
StrVal: string;
BoolVal: Boolean;
end;
var
value: TValue;
begin
value.Kind := VKString;
value.StrVal := 'hello';
case value.Kind of
VKInteger: writeln(value.IntVal);
VKString: writeln(value.StrVal);
VKBoolean: writeln(value.BoolVal);
end;
end. type Value = number | string | boolean;
function describe(value: Value): void {
if (typeof value === "number")
console.log("number:", value);
else if (typeof value === "string")
console.log("string:", value);
else
console.log("boolean:", value);
}
describe(42);
describe("hello");
describe(true); Pascal uses variant records (a record with a discriminant tag and overlapping fields) to represent values of multiple types. TypeScript has first-class union types (
number | string | boolean) which are checked with typeof guards. TypeScript discriminated unions (type Shape = { kind: "circle", radius: number } | { kind: "square", side: number }) are the idiomatic equivalent of Pascal's variant records — and much cleaner to use.Generics
program GenericsDemo;
type
generic TBox<T> = class
private
FValue: T;
public
constructor Create(value: T);
function GetValue: T;
end;
constructor TBox.Create(value: T);
begin
FValue := value;
end;
function TBox.GetValue: T;
begin
Result := FValue;
end;
var
numberBox: specialize TBox<Integer>;
wordBox: specialize TBox<string>;
begin
numberBox := specialize TBox<Integer>.Create(42);
wordBox := specialize TBox<string>.Create('hello');
writeln(numberBox.GetValue);
writeln(wordBox.GetValue);
numberBox.Free;
wordBox.Free;
end. class Box<T> {
constructor(private value: T) {}
getValue(): T { return this.value; }
}
const numberBox = new Box<number>(42);
const wordBox = new Box<string>("hello");
console.log(numberBox.getValue());
console.log(wordBox.getValue());
// Generic function:
function identity<T>(value: T): T { return value; }
console.log(identity(100));
console.log(identity("world")); Both languages support generics with type parameters. Free Pascal uses
generic and specialize keywords; TypeScript uses angle-bracket syntax consistently. TypeScript generics are erased at runtime (like Java), while Pascal generics generate separate compiled code per type (like C++ templates). TypeScript generic constraints use extends: function largest<T extends { length: number }>(items: T[]).Error Handling
Try / Except (Catch)
program TryExcept;
uses SysUtils;
var
result: Integer;
begin
try
result := StrToInt('not a number');
writeln(result);
except
on error: EConvertError do
writeln('Conversion error: ', error.Message);
on error: Exception do
writeln('Unknown error: ', error.Message);
end;
end. try {
const result = parseInt("not a number", 10);
if (isNaN(result)) throw new TypeError("Invalid number");
console.log(result);
} catch (error) {
if (error instanceof TypeError)
console.log("Type error:", (error as TypeError).message);
else
console.log("Unknown error:", error);
} Both languages use try/catch (Pascal calls it try/except). Pascal supports typed catches with
on ErrorVar: ExceptionClass do; TypeScript's catch receives an unknown type that must be narrowed with instanceof. Note that TypeScript's parseInt does not throw on invalid input — it returns NaN — so explicit validation is often needed, unlike Pascal's StrToInt which throws EConvertError.Custom Error Types
program CustomException;
uses SysUtils;
type
EValidationError = class(Exception)
private
FFieldName: string;
public
constructor Create(fieldName, messageText: string);
property FieldName: string read FFieldName;
end;
constructor EValidationError.Create(fieldName, messageText: string);
begin
inherited Create(messageText);
FFieldName := fieldName;
end;
begin
try
raise EValidationError.Create('email', 'Invalid format');
except
on error: EValidationError do
writeln('Field "', error.FieldName, '": ', error.Message);
end;
end. class ValidationError extends Error {
constructor(
public readonly fieldName: string,
message: string,
) {
super(message);
this.name = "ValidationError";
}
}
try {
throw new ValidationError("email", "Invalid format");
} catch (error) {
if (error instanceof ValidationError)
console.log(`Field "${error.fieldName}": ${error.message}`);
} Custom exceptions follow the same pattern in both languages: extend the base exception class, add properties, and call the parent constructor. Pascal's convention names exception classes with an
E prefix (EValidationError); TypeScript's convention uses an Error suffix (ValidationError). Setting this.name in TypeScript is recommended so error.name identifies the type correctly in logs.Finally Block
program TryFinally;
uses SysUtils;
var
resource: string;
begin
resource := 'open';
try
try
writeln('Using resource');
raise Exception.Create('Something went wrong');
finally
resource := 'closed';
writeln('Resource: ', resource);
end;
except
on error: Exception do
writeln('Caught: ', error.Message);
end;
end. let resource = "open";
try {
console.log("Using resource");
throw new Error("Something went wrong");
} catch (error) {
console.log("Caught:", (error as Error).message);
} finally {
resource = "closed";
console.log("Resource:", resource);
} Both languages support
finally blocks that execute regardless of whether an exception was raised. Pascal's try...finally is structurally separate from try...except — to both handle an exception and clean up, you must nest them or use try...except...finally (Free Pascal supports this). TypeScript combines catch and finally in a single try block naturally.Modules
Importing from a Module
program ModuleDemo;
uses
SysUtils, { string conversion, date/time }
Math, { mathematical functions }
StrUtils; { string utilities }
begin
writeln(Format('Pi = %.4f', [Pi]));
writeln(Max(10, 20));
writeln(UpperCase('hello'));
end. // Named imports:
import { readFileSync } from "fs";
import { join } from "path";
// Default import:
// import lodash from "lodash";
// Namespace import:
// import * as math from "mathjs";
// (This example uses node builtins — norun in browser)
console.log(join("/tmp", "file.txt")); Pascal's
uses clause imports entire units; all their exported identifiers become available in the current scope. TypeScript uses ES module syntax: import { name } from "module" for named exports, import Default from "module" for a default export, and import * as ns from "module" to import everything under a namespace. TypeScript modules are files — each file is its own module.Exporting from a Module
{ Pascal unit structure:
unit MathUtils;
interface { public declarations }
function Square(n: Integer): Integer;
function Cube(n: Integer): Integer;
implementation { private implementation }
function Square(n: Integer): Integer;
begin Result := n * n; end;
function Cube(n: Integer): Integer;
begin Result := n * n * n; end;
end. } // mathUtils.ts
export function square(n: number): number { return n * n; }
export function cube(n: number): number { return n * n * n; }
export const PI = 3.14159265;
// Consumer:
// import { square, cube } from "./mathUtils"; Pascal units have a strict interface/implementation split: the
interface section declares what is public; the implementation section provides the bodies (and can also contain private helpers not in the interface). TypeScript exports individual declarations with the export keyword. Types, functions, classes, constants, and variables can all be exported; anything without export is private to the file.