13 KiB
Executable File
TypeScript Introduction for Python Developers
A practical guide to TypeScript, written for Python developers.
Table of Contents
- What is TypeScript?
- Strengths & Weaknesses
- Typical Use Cases
- Basic Syntax
- Arrays
- Handling Null and Undefined
- Strings and Template Literals
- Guard Clauses and Validation
- Date Handling
- Code Style
- Quick Reference: Python to TypeScript
What is TypeScript?
TypeScript is a superset of JavaScript that adds static type checking. Your TypeScript code compiles (transpiles) to plain JavaScript, which then runs in browsers, Node.js, or anywhere JavaScript runs.
// TypeScript (what you write)
function greet(name: string): string {
return `Hello, ${name}`;
}
// JavaScript (what runs)
function greet(name) {
return "Hello, " + name;
}
The key difference from Python: TypeScript checks types at compile time, while Python checks types at runtime. This means many bugs are caught before your code runs.
Strengths & Weaknesses
Strengths
| Benefit | Description |
|---|---|
| Early bug detection | Type errors are caught during development, not in production |
| Better IDE support | Autocomplete, inline docs, and refactoring work reliably |
| Self-documenting code | Types serve as living documentation |
| Safer refactoring | Rename a function and the compiler finds all call sites |
| Gradual adoption | Add TypeScript to existing JavaScript projects incrementally |
Weaknesses
| Drawback | Description |
|---|---|
| Compilation step | Requires a build process (though often simple) |
| Learning curve | Advanced types can be complex |
| Boilerplate | Type annotations add extra syntax |
| Type system limits | Complex runtime patterns may not fit static typing easily |
Comparison with Python
| Aspect | TypeScript | Python |
|---|---|---|
| Typing | Static (compile time) | Dynamic (runtime) |
| Type inference | Yes (often inferrable) | Yes (via type hints) |
| Null safety | Optional (strict mode) | Via type hints |
| Null representation | null, undefined |
None |
| Execution | Compiles to JS | Interpreted |
Typical Use Cases
TypeScript shines in:
- Frontend web applications (React, Vue, Angular all support TypeScript)
- Node.js backends (APIs, microservices)
- Large codebases where refactoring and maintenance matter
- Teams where code review and shared understanding are important
- Projects needing stability (banking, healthcare, enterprise software)
Python still leads in data science, ML/AI, scripting, and rapid prototyping.
Basic Syntax
Variables: const and let
TypeScript uses const for variables that won't be reassigned, and let for those that will. Avoid var.
const apiBase = 'https://api.example.com'; // Cannot be reassigned
let count = 0; // Can be reassigned
count = count + 1;
Important: const prevents reassignment but doesn't make objects immutable:
const config = { retries: 2 };
config.retries = 3; // Allowed: mutating the object
// config = {}; // Error: reassigning the variable
Python comparison:
API_BASE = 'https://api.example.com' # Convention only, not enforced
count = 0
Functions
Basic function declaration with type annotations:
function greet(name: string): string {
return `Hello, ${name}`;
}
With optional parameters and defaults:
function buildWeeklyPeriods(
dateRange?: DateRange,
now = new Date(),
): string[] {
// ...
}
?:marks a parameter as optional= valueprovides a default: typedeclares the return type
Python comparison:
def greet(name: str) -> str:
return f"Hello, {name}"
def build_weekly_periods(date_range=None, now=None):
if now is None:
now = datetime.now()
Type Annotations
Type annotations come after the variable/parameter name (opposite of Python):
const name: string = 'Alice';
const age: number = 30;
const isActive: boolean = true;
Common basic types:
| TypeScript | Python | Description |
|---|---|---|
string |
str |
Text |
number |
int / float |
All numbers |
boolean |
bool |
True / False |
undefined |
— | Uninitialized |
null |
None |
Intentional absence |
string[] |
List[str] |
Array of strings |
Arrays
TypeScript arrays are typed and support the same operations as Python lists.
const parts = [
{ type: 'year', value: '2026' },
{ type: 'month', value: '03' },
{ type: 'day', value: '24' },
];
// Access by index
const first = parts[0];
// Array length
const count = parts.length;
Array Methods: find, filter, map, flatMap
find — Get the first matching element:
const yearPart = parts.find((part) => part.type === 'year');
console.log(yearPart); // { type: 'year', value: '2026' }
Returns undefined if no match found.
Python comparison:
year_part = next((p for p in parts if p['type'] == 'year'), None)
filter — Keep matching elements:
const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter((n) => n % 2 === 0);
console.log(evens); // [2, 4]
map — Transform each element:
const doubled = numbers.map((n) => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
flatMap — Filter and transform in one pass:
const result = periodStarts.flatMap((start, index) => {
if (!isInRange(start)) {
return []; // Drop this element
}
return `${start.toISOString()}/${end.toISOString()}`; // Transform
});
Returning [] removes the element; returning a value keeps it.
Python comparison:
filtered = [s for s in period_starts if in_range(s)]
result = [make_interval(s) for s in filtered]
Slicing and Indexing
const alignedStarts: Date[] = [];
// Slice: from start to before last element
const periodStarts = alignedStarts.slice(0, -1);
// Index access
const start = alignedStarts[index];
const end = alignedStarts[index + 1];
Python comparison:
period_starts = aligned_starts[:-1]
start = aligned_starts[index]
end = aligned_starts[index + 1]
Handling Null and Undefined
TypeScript has two "nothing" values: null (explicitly set) and undefined (not yet assigned). Python only has None.
Optional Chaining ?.
Safely access properties that might not exist:
const user: { profile?: { city?: string } } = {};
const city = user.profile?.city; // undefined, no crash
Without ?., accessing user.profile.city when profile is undefined would throw an error.
Python comparison:
city = user.profile.city if user and user.profile else None
Nullish Coalescing ??
Provide a fallback only when the value is null or undefined:
const name = maybeName ?? 'anonymous';
Key difference from ||:
'' || 'fallback'; // 'fallback' (empty string is falsy)
'' ?? 'fallback'; // '' (only null/undefined trigger fallback)
0 || 'fallback'; // 'fallback'
0 ?? 'fallback'; // 0
Python comparison:
name = x if x is not None else 'fallback'
Combining Operators for Robust Code
These operators work great together:
const year = parts.find((part) => part.type === 'year')?.value ?? '';
Breaking it down:
find(...)returnsundefinedif no match?.valuesafely accessesvalue(or returnsundefined)?? ''provides a fallback string
This pattern is extremely common in TypeScript code.
Strings and Template Literals
String Literals
const a = 'single quotes';
const b = "double quotes"; // Both are valid
const c = ''; // Empty string
Template Literals
Use backticks for string interpolation:
const year = '2026';
const month = '03';
const day = '24';
const label = `${year}-${month}-${day}`;
console.log(label); // '2026-03-24'
Template literals also support multi-line strings:
const html = `
<div>
<h1>Title</h1>
</div>
`;
Python comparison:
label = f"{year}-{month}-{day}"
html = """
<div>
<h1>Title</h1>
</div>
"""
Guard Clauses and Validation
Guard clauses exit early when conditions are not met:
if (rangeStart !== undefined && rangeEnd !== undefined && rangeStart > rangeEnd) {
return [];
}
!==— strict "not equal" (use this, not!=)===— strict "equal" (use this, not==)
1 === 1; // true
1 === '1'; // false (different types)
0 === false; // false (different types)
Always prefer strict equality (=== / !==) to avoid subtle type coercion bugs.
Python comparison:
if range_start is not None and range_end is not None and range_start > range_end:
return []
Date Handling
Getting Timestamps
const startTime = start.getTime();
Returns milliseconds since Unix epoch (1970-01-01).
Compare timestamps directly:
if (startTime >= rangeStart && startTime <= rangeEnd) {
// ...
}
Converting to ISO Strings
const interval = `${start.toISOString()}/${end.toISOString()}`;
Output:
2026-03-23T23:00:00.000Z/2026-03-30T22:00:00.000Z
The Z indicates UTC timezone.
Python comparison:
start_ts_ms = int(start_dt.timestamp() * 1000)
interval = f"{start.isoformat()}/{end.isoformat()}"
Code Style
Semicolons
TypeScript/JavaScript allows optional semicolons. Most projects choose one style and stick with it:
// With semicolons (common in TypeScript)
const x = 1;
const y = 2;
// Without semicolons (also valid)
const x = 1
const y = 2
Follow your project's convention. Most TypeScript projects use semicolons.
Equality
| Operator | Use case |
|---|---|
=== |
Always use for comparisons (strict equality) |
!== |
Always use for comparisons (strict inequality) |
== |
Avoid (allows type coercion) |
!= |
Avoid (allows type coercion) |
Robust Patterns
The idiomatic way to safely extract values:
function safePart(parts: Part[], wanted: string): string {
return parts.find((p) => p.type === wanted)?.value ?? '';
}
This function:
- Returns
undefinedif no matching part exists - Uses
?.to safely access.value - Uses
?? ''to ensure a string is always returned
Quick Reference: Python to TypeScript
Functions
def fn(x: int) -> str:
return str(x)
function fn(x: number): string {
return String(x);
}
Lambda / Arrow Functions
lambda x: x + 1
(x) => x + 1
Fallback for Missing Values
value = x if x is not None else 'fallback'
const value = x ?? 'fallback';
String Interpolation
f"{year}-{month}-{day}"
`${year}-${month}-${day}`
Find First Match
next((p for p in parts if p['type'] == 'year'), None)
parts.find((p) => p.type === 'year')
Array Filtering
filtered = [x for x in items if x.active]
const filtered = items.filter((x) => x.active);
Array Mapping
mapped = [x.name for x in items]
const mapped = items.map((x) => x.name);
None Checks
if user and user.profile:
city = user.profile.city
else:
city = None
const city = user.profile?.city;
Return Type Annotations
from typing import List
def get_names() -> List[str]:
return ['Alice', 'Bob']
function getNames(): string[] {
return ['Alice', 'Bob'];
}
Next Steps
Now that you understand the fundamentals, explore:
- Interfaces and Types — Define custom shapes for your data
- Generics — Write reusable functions that work with any type
- Enums — Define fixed sets of values
- Modules — Organize code across files
- TypeScript with React/Vue/Node — Apply these concepts in real frameworks
Based on TypeScript learning notes from the d-fine vault.