init at work
This commit is contained in:
Executable
+606
@@ -0,0 +1,606 @@
|
||||
# TypeScript Introduction for Python Developers
|
||||
|
||||
A practical guide to TypeScript, written for Python developers.
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [What is TypeScript?](#what-is-typescript)
|
||||
2. [Strengths & Weaknesses](#strengths--weaknesses)
|
||||
3. [Typical Use Cases](#typical-use-cases)
|
||||
4. [Basic Syntax](#basic-syntax)
|
||||
- [Variables: `const` and `let`](#variables-const-and-let)
|
||||
- [Functions](#functions)
|
||||
- [Type Annotations](#type-annotations)
|
||||
5. [Arrays](#arrays)
|
||||
- [Array Methods: `find`, `filter`, `map`, `flatMap`](#array-methods-find-filter-map-flatmap)
|
||||
- [Slicing and Indexing](#slicing-and-indexing)
|
||||
6. [Handling Null and Undefined](#handling-null-and-undefined)
|
||||
- [Optional Chaining `?.`](#optional-chaining-)
|
||||
- [Nullish Coalescing `??`](#nullish-coalescing-)
|
||||
7. [Strings and Template Literals](#strings-and-template-literals)
|
||||
8. [Guard Clauses and Validation](#guard-clauses-and-validation)
|
||||
9. [Date Handling](#date-handling)
|
||||
10. [Code Style](#code-style)
|
||||
11. [Quick Reference: Python to TypeScript](#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.
|
||||
|
||||
```ts
|
||||
// TypeScript (what you write)
|
||||
function greet(name: string): string {
|
||||
return `Hello, ${name}`;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
// 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`.
|
||||
|
||||
```ts
|
||||
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:
|
||||
|
||||
```ts
|
||||
const config = { retries: 2 };
|
||||
config.retries = 3; // Allowed: mutating the object
|
||||
// config = {}; // Error: reassigning the variable
|
||||
```
|
||||
|
||||
**Python comparison:**
|
||||
```python
|
||||
API_BASE = 'https://api.example.com' # Convention only, not enforced
|
||||
count = 0
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
Basic function declaration with type annotations:
|
||||
|
||||
```ts
|
||||
function greet(name: string): string {
|
||||
return `Hello, ${name}`;
|
||||
}
|
||||
```
|
||||
|
||||
With optional parameters and defaults:
|
||||
|
||||
```ts
|
||||
function buildWeeklyPeriods(
|
||||
dateRange?: DateRange,
|
||||
now = new Date(),
|
||||
): string[] {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
- `?:` marks a parameter as optional
|
||||
- `= value` provides a default
|
||||
- `: type` declares the return type
|
||||
|
||||
**Python comparison:**
|
||||
```python
|
||||
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):
|
||||
|
||||
```ts
|
||||
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.
|
||||
|
||||
```ts
|
||||
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:
|
||||
|
||||
```ts
|
||||
const yearPart = parts.find((part) => part.type === 'year');
|
||||
console.log(yearPart); // { type: 'year', value: '2026' }
|
||||
```
|
||||
|
||||
Returns `undefined` if no match found.
|
||||
|
||||
**Python comparison:**
|
||||
```python
|
||||
year_part = next((p for p in parts if p['type'] == 'year'), None)
|
||||
```
|
||||
|
||||
**`filter`** — Keep matching elements:
|
||||
|
||||
```ts
|
||||
const numbers = [1, 2, 3, 4, 5];
|
||||
const evens = numbers.filter((n) => n % 2 === 0);
|
||||
console.log(evens); // [2, 4]
|
||||
```
|
||||
|
||||
**`map`** — Transform each element:
|
||||
|
||||
```ts
|
||||
const doubled = numbers.map((n) => n * 2);
|
||||
console.log(doubled); // [2, 4, 6, 8, 10]
|
||||
```
|
||||
|
||||
**`flatMap`** — Filter and transform in one pass:
|
||||
|
||||
```ts
|
||||
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:**
|
||||
```python
|
||||
filtered = [s for s in period_starts if in_range(s)]
|
||||
result = [make_interval(s) for s in filtered]
|
||||
```
|
||||
|
||||
### Slicing and Indexing
|
||||
|
||||
```ts
|
||||
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:**
|
||||
```python
|
||||
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:
|
||||
|
||||
```ts
|
||||
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:**
|
||||
```python
|
||||
city = user.profile.city if user and user.profile else None
|
||||
```
|
||||
|
||||
### Nullish Coalescing `??`
|
||||
|
||||
Provide a fallback only when the value is `null` or `undefined`:
|
||||
|
||||
```ts
|
||||
const name = maybeName ?? 'anonymous';
|
||||
```
|
||||
|
||||
Key difference from `||`:
|
||||
|
||||
```ts
|
||||
'' || 'fallback'; // 'fallback' (empty string is falsy)
|
||||
'' ?? 'fallback'; // '' (only null/undefined trigger fallback)
|
||||
0 || 'fallback'; // 'fallback'
|
||||
0 ?? 'fallback'; // 0
|
||||
```
|
||||
|
||||
**Python comparison:**
|
||||
```python
|
||||
name = x if x is not None else 'fallback'
|
||||
```
|
||||
|
||||
### Combining Operators for Robust Code
|
||||
|
||||
These operators work great together:
|
||||
|
||||
```ts
|
||||
const year = parts.find((part) => part.type === 'year')?.value ?? '';
|
||||
```
|
||||
|
||||
Breaking it down:
|
||||
1. `find(...)` returns `undefined` if no match
|
||||
2. `?.value` safely accesses `value` (or returns `undefined`)
|
||||
3. `?? ''` provides a fallback string
|
||||
|
||||
This pattern is **extremely common** in TypeScript code.
|
||||
|
||||
---
|
||||
|
||||
## Strings and Template Literals
|
||||
|
||||
### String Literals
|
||||
|
||||
```ts
|
||||
const a = 'single quotes';
|
||||
const b = "double quotes"; // Both are valid
|
||||
const c = ''; // Empty string
|
||||
```
|
||||
|
||||
### Template Literals
|
||||
|
||||
Use backticks for string interpolation:
|
||||
|
||||
```ts
|
||||
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:
|
||||
|
||||
```ts
|
||||
const html = `
|
||||
<div>
|
||||
<h1>Title</h1>
|
||||
</div>
|
||||
`;
|
||||
```
|
||||
|
||||
**Python comparison:**
|
||||
```python
|
||||
label = f"{year}-{month}-{day}"
|
||||
html = """
|
||||
<div>
|
||||
<h1>Title</h1>
|
||||
</div>
|
||||
"""
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Guard Clauses and Validation
|
||||
|
||||
Guard clauses exit early when conditions are not met:
|
||||
|
||||
```ts
|
||||
if (rangeStart !== undefined && rangeEnd !== undefined && rangeStart > rangeEnd) {
|
||||
return [];
|
||||
}
|
||||
```
|
||||
|
||||
- `!==` — strict "not equal" (use this, not `!=`)
|
||||
- `===` — strict "equal" (use this, not `==`)
|
||||
|
||||
```ts
|
||||
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:**
|
||||
```python
|
||||
if range_start is not None and range_end is not None and range_start > range_end:
|
||||
return []
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Date Handling
|
||||
|
||||
### Getting Timestamps
|
||||
|
||||
```ts
|
||||
const startTime = start.getTime();
|
||||
```
|
||||
|
||||
Returns milliseconds since Unix epoch (1970-01-01).
|
||||
|
||||
Compare timestamps directly:
|
||||
|
||||
```ts
|
||||
if (startTime >= rangeStart && startTime <= rangeEnd) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Converting to ISO Strings
|
||||
|
||||
```ts
|
||||
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:**
|
||||
```python
|
||||
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:
|
||||
|
||||
```ts
|
||||
// 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:
|
||||
|
||||
```ts
|
||||
function safePart(parts: Part[], wanted: string): string {
|
||||
return parts.find((p) => p.type === wanted)?.value ?? '';
|
||||
}
|
||||
```
|
||||
|
||||
This function:
|
||||
- Returns `undefined` if no matching part exists
|
||||
- Uses `?.` to safely access `.value`
|
||||
- Uses `?? ''` to ensure a string is always returned
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference: Python to TypeScript
|
||||
|
||||
### Functions
|
||||
|
||||
```python
|
||||
def fn(x: int) -> str:
|
||||
return str(x)
|
||||
```
|
||||
|
||||
```ts
|
||||
function fn(x: number): string {
|
||||
return String(x);
|
||||
}
|
||||
```
|
||||
|
||||
### Lambda / Arrow Functions
|
||||
|
||||
```python
|
||||
lambda x: x + 1
|
||||
```
|
||||
|
||||
```ts
|
||||
(x) => x + 1
|
||||
```
|
||||
|
||||
### Fallback for Missing Values
|
||||
|
||||
```python
|
||||
value = x if x is not None else 'fallback'
|
||||
```
|
||||
|
||||
```ts
|
||||
const value = x ?? 'fallback';
|
||||
```
|
||||
|
||||
### String Interpolation
|
||||
|
||||
```python
|
||||
f"{year}-{month}-{day}"
|
||||
```
|
||||
|
||||
```ts
|
||||
`${year}-${month}-${day}`
|
||||
```
|
||||
|
||||
### Find First Match
|
||||
|
||||
```python
|
||||
next((p for p in parts if p['type'] == 'year'), None)
|
||||
```
|
||||
|
||||
```ts
|
||||
parts.find((p) => p.type === 'year')
|
||||
```
|
||||
|
||||
### Array Filtering
|
||||
|
||||
```python
|
||||
filtered = [x for x in items if x.active]
|
||||
```
|
||||
|
||||
```ts
|
||||
const filtered = items.filter((x) => x.active);
|
||||
```
|
||||
|
||||
### Array Mapping
|
||||
|
||||
```python
|
||||
mapped = [x.name for x in items]
|
||||
```
|
||||
|
||||
```ts
|
||||
const mapped = items.map((x) => x.name);
|
||||
```
|
||||
|
||||
### None Checks
|
||||
|
||||
```python
|
||||
if user and user.profile:
|
||||
city = user.profile.city
|
||||
else:
|
||||
city = None
|
||||
```
|
||||
|
||||
```ts
|
||||
const city = user.profile?.city;
|
||||
```
|
||||
|
||||
### Return Type Annotations
|
||||
|
||||
```python
|
||||
from typing import List
|
||||
|
||||
def get_names() -> List[str]:
|
||||
return ['Alice', 'Bob']
|
||||
```
|
||||
|
||||
```ts
|
||||
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.*
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# TypeScript Learning Index (Python -> TypeScript)
|
||||
|
||||
## Foundations
|
||||
|
||||
- `01-function-declaration-syntax.md`
|
||||
- `02-const-and-assignment.md`
|
||||
- `03-dot-access-and-method-calls.md`
|
||||
- `04-array-find-and-arrow-functions.md`
|
||||
- `05-strict-equality-operator.md`
|
||||
- `06-optional-chaining-operator.md`
|
||||
- `07-nullish-coalescing-operator.md`
|
||||
- `08-string-literals.md`
|
||||
- `09-template-literals.md`
|
||||
- `10-semicolons.md`
|
||||
- `11-robust-formatting-style.md`
|
||||
- `12-python-to-typescript-mini-map.md`
|
||||
|
||||
## Date/Interval Logic from your code
|
||||
|
||||
- `13-optional-params-and-default-values.md`
|
||||
- `14-return-type-array-strings.md`
|
||||
- `15-array-slice-and-indexing.md`
|
||||
- `16-timestamps-with-gettime.md`
|
||||
- `17-guard-clauses-and-range-validation.md`
|
||||
- `18-flatmap-filter-and-map-pattern.md`
|
||||
- `19-iso-strings-and-template-literals.md`
|
||||
- `20-alignedstarts-concept.md`
|
||||
|
||||
Recommended order: start at `01`, then jump to `13-20` while reading `jsonDownload.ts`.
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
# Function Declaration Syntax in TypeScript
|
||||
|
||||
A function declaration defines a reusable block of logic with typed inputs and output.
|
||||
|
||||
## Basic Shape
|
||||
|
||||
```ts
|
||||
function greet(name: string): string {
|
||||
return `Hello, ${name}`;
|
||||
}
|
||||
```
|
||||
|
||||
## Parts Explained
|
||||
|
||||
- `function`: keyword to declare a function.
|
||||
- `greet`: function name.
|
||||
- `(name: string)`: parameter list with a type annotation.
|
||||
- `: string`: return type annotation.
|
||||
- `{ ... }`: function body.
|
||||
|
||||
## Python Comparison
|
||||
|
||||
```py
|
||||
def greet(name: str) -> str:
|
||||
return f"Hello, {name}"
|
||||
```
|
||||
|
||||
TypeScript puts type annotations after variable names as `name: string`, similar to Python type hints.
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
# `const` and Assignment
|
||||
|
||||
TypeScript uses `const`, `let`, and `var` for variable declarations. Modern code usually prefers `const` and `let`.
|
||||
|
||||
## `const`
|
||||
|
||||
```ts
|
||||
const apiBase = 'https://example.com';
|
||||
```
|
||||
|
||||
- `const` means the binding cannot be reassigned.
|
||||
- You can still mutate object contents unless frozen.
|
||||
|
||||
```ts
|
||||
const config = { retries: 2 };
|
||||
config.retries = 3; // allowed
|
||||
// config = {}; // not allowed
|
||||
```
|
||||
|
||||
## Assignment Operator `=`
|
||||
|
||||
```ts
|
||||
let count = 0;
|
||||
count = count + 1;
|
||||
```
|
||||
|
||||
- `=` assigns a new value to a variable.
|
||||
|
||||
## Python Comparison
|
||||
|
||||
Python has no enforced `const`; TypeScript enforces no-reassign when `const` is used.
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
# Dot Access and Method Calls
|
||||
|
||||
Dot notation accesses properties and methods on objects.
|
||||
|
||||
## Property Access
|
||||
|
||||
```ts
|
||||
const user = { name: 'Mathias', age: 30 };
|
||||
console.log(user.name); // 'Mathias'
|
||||
```
|
||||
|
||||
## Method Call
|
||||
|
||||
```ts
|
||||
const text = 'hello';
|
||||
console.log(text.toUpperCase()); // 'HELLO'
|
||||
```
|
||||
|
||||
In your code:
|
||||
|
||||
```ts
|
||||
backendPeriodLabelFormatter.formatToParts(date)
|
||||
```
|
||||
|
||||
- `backendPeriodLabelFormatter` is an object.
|
||||
- `formatToParts` is a method.
|
||||
- `(date)` passes the argument.
|
||||
|
||||
## Python Comparison
|
||||
|
||||
Equivalent idea to `obj.attr` and `obj.method(arg)`.
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
# Array `find` and Arrow Functions
|
||||
|
||||
`Array.prototype.find` returns the first element that matches a condition.
|
||||
|
||||
## Example
|
||||
|
||||
```ts
|
||||
const parts = [
|
||||
{ type: 'year', value: '2026' },
|
||||
{ type: 'month', value: '03' },
|
||||
{ type: 'day', value: '24' },
|
||||
];
|
||||
|
||||
const yearPart = parts.find((part) => part.type === 'year');
|
||||
console.log(yearPart); // { type: 'year', value: '2026' }
|
||||
```
|
||||
|
||||
## Arrow Function Syntax
|
||||
|
||||
```ts
|
||||
(part) => part.type === 'year'
|
||||
```
|
||||
|
||||
- `(part)`: parameter.
|
||||
- `=>`: arrow token.
|
||||
- `part.type === 'year'`: expression result (`true` or `false`).
|
||||
|
||||
If no item matches, `find` returns `undefined`.
|
||||
|
||||
## Python Comparison
|
||||
|
||||
Similar to:
|
||||
|
||||
```py
|
||||
year_part = next((p for p in parts if p['type'] == 'year'), None)
|
||||
```
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# Strict Equality Operator `===`
|
||||
|
||||
TypeScript/JavaScript have both `==` and `===`.
|
||||
|
||||
Use `===` for predictable behavior.
|
||||
|
||||
## Examples
|
||||
|
||||
```ts
|
||||
1 === 1; // true
|
||||
1 === '1'; // false
|
||||
0 === false; // false
|
||||
```
|
||||
|
||||
`===` compares both value and type, and avoids implicit coercion.
|
||||
|
||||
## Why it matters
|
||||
|
||||
Using `===` prevents subtle bugs caused by automatic conversions.
|
||||
|
||||
## Python Comparison
|
||||
|
||||
Closest to Python `==`, which does not coerce strings/numbers the JavaScript way.
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# Optional Chaining Operator `?.`
|
||||
|
||||
Optional chaining safely accesses properties/methods when a value might be `null` or `undefined`.
|
||||
|
||||
## Property Access
|
||||
|
||||
```ts
|
||||
const user: { profile?: { city?: string } } = {};
|
||||
const city = user.profile?.city;
|
||||
console.log(city); // undefined
|
||||
```
|
||||
|
||||
## Method Call
|
||||
|
||||
```ts
|
||||
const maybeFn: undefined | (() => string) = undefined;
|
||||
const value = maybeFn?.();
|
||||
console.log(value); // undefined
|
||||
```
|
||||
|
||||
Without `?.`, these would throw runtime errors.
|
||||
|
||||
## Python Comparison
|
||||
|
||||
Similar intent to:
|
||||
|
||||
```py
|
||||
city = user.profile.city if user and user.profile else None
|
||||
```
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# Nullish Coalescing Operator `??`
|
||||
|
||||
`??` provides a fallback only when the left side is `null` or `undefined`.
|
||||
|
||||
## Example
|
||||
|
||||
```ts
|
||||
const maybeName: string | undefined = undefined;
|
||||
const name = maybeName ?? 'anonymous';
|
||||
console.log(name); // 'anonymous'
|
||||
```
|
||||
|
||||
## Difference from `||`
|
||||
|
||||
```ts
|
||||
'' || 'fallback'; // 'fallback'
|
||||
'' ?? 'fallback'; // ''
|
||||
```
|
||||
|
||||
- `||` treats many falsy values as missing (`''`, `0`, `false`).
|
||||
- `??` treats only `null` and `undefined` as missing.
|
||||
|
||||
In your formatter code, `?? ''` is used as a safe fallback.
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
# String Literals
|
||||
|
||||
String literals are text values written directly in code.
|
||||
|
||||
## Examples
|
||||
|
||||
```ts
|
||||
const a = 'year';
|
||||
const b = "month";
|
||||
const c = '';
|
||||
```
|
||||
|
||||
`''` is an empty string.
|
||||
|
||||
## Typical Uses
|
||||
|
||||
- Labels and constants.
|
||||
- Comparisons.
|
||||
- Fallback values.
|
||||
|
||||
## Good Practice
|
||||
|
||||
Keep quote style consistent with project conventions.
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
# Template Literals
|
||||
|
||||
Template literals are strings enclosed by backticks and support interpolation.
|
||||
|
||||
## Syntax
|
||||
|
||||
```ts
|
||||
const year = '2026';
|
||||
const month = '03';
|
||||
const day = '24';
|
||||
|
||||
const label = `${year}-${month}-${day}`;
|
||||
console.log(label); // '2026-03-24'
|
||||
```
|
||||
|
||||
## Why use them
|
||||
|
||||
- Easier than concatenation.
|
||||
- More readable for multi-part strings.
|
||||
- Supports multiline text.
|
||||
|
||||
## Python Comparison
|
||||
|
||||
Equivalent concept to Python f-strings:
|
||||
|
||||
```py
|
||||
label = f"{year}-{month}-{day}"
|
||||
```
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
# Semicolons in TypeScript
|
||||
|
||||
Semicolons terminate statements.
|
||||
|
||||
## Example
|
||||
|
||||
```ts
|
||||
const x = 1;
|
||||
const y = 2;
|
||||
const z = x + y;
|
||||
```
|
||||
|
||||
JavaScript has automatic semicolon insertion, but many teams still use explicit semicolons for consistency and fewer edge-case surprises.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Follow the style already used in your repository.
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# Why This Formatting Pattern Is Robust
|
||||
|
||||
The pattern in your code combines `find`, `?.`, and `??`:
|
||||
|
||||
```ts
|
||||
const year = parts.find((part) => part.type === 'year')?.value ?? '';
|
||||
```
|
||||
|
||||
## Why this is robust
|
||||
|
||||
- `find(...)` may return `undefined`.
|
||||
- `?.value` prevents a crash when no part exists.
|
||||
- `?? ''` guarantees a string fallback.
|
||||
|
||||
This keeps `formatPeriodStartLabel(...)` stable even when input parts are incomplete.
|
||||
|
||||
## End-to-End Example
|
||||
|
||||
```ts
|
||||
function safePart(parts: Intl.DateTimeFormatPart[], wanted: string): string {
|
||||
return parts.find((p) => p.type === wanted)?.value ?? '';
|
||||
}
|
||||
```
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# Python to TypeScript Mini Map
|
||||
|
||||
Quick syntax map for common constructs.
|
||||
|
||||
## Function typing
|
||||
|
||||
```py
|
||||
def fn(x: int) -> str:
|
||||
return str(x)
|
||||
```
|
||||
|
||||
```ts
|
||||
function fn(x: number): string {
|
||||
return String(x);
|
||||
}
|
||||
```
|
||||
|
||||
## Lambda / Arrow
|
||||
|
||||
```py
|
||||
lambda x: x + 1
|
||||
```
|
||||
|
||||
```ts
|
||||
(x) => x + 1
|
||||
```
|
||||
|
||||
## Fallback for missing values
|
||||
|
||||
```py
|
||||
value = x if x is not None else 'fallback'
|
||||
```
|
||||
|
||||
```ts
|
||||
const value = x ?? 'fallback';
|
||||
```
|
||||
|
||||
## String interpolation
|
||||
|
||||
```py
|
||||
f"{year}-{month}-{day}"
|
||||
```
|
||||
|
||||
```ts
|
||||
`${year}-${month}-${day}`
|
||||
```
|
||||
|
||||
## Searching first match
|
||||
|
||||
```py
|
||||
next((p for p in parts if p['type'] == 'year'), None)
|
||||
```
|
||||
|
||||
```ts
|
||||
parts.find((p) => p.type === 'year')
|
||||
```
|
||||
@@ -0,0 +1,32 @@
|
||||
# Optional Parameters and Default Values in TypeScript
|
||||
|
||||
In TypeScript, a function parameter can be optional and can also have a default value.
|
||||
|
||||
## Example from your code
|
||||
|
||||
```ts
|
||||
function buildWeeklyDownloadPeriods(
|
||||
dateRange?: DownloadDateRange,
|
||||
now = new Date(),
|
||||
): string[] {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## What this means
|
||||
|
||||
- `dateRange?`:
|
||||
- The `?` means this argument is optional.
|
||||
- The caller can omit it.
|
||||
- `now = new Date()`:
|
||||
- If caller does not pass `now`, TypeScript uses `new Date()`.
|
||||
|
||||
## Python comparison
|
||||
|
||||
```py
|
||||
def build_weekly_download_periods(date_range=None, now=None):
|
||||
if now is None:
|
||||
now = datetime.now()
|
||||
```
|
||||
|
||||
TypeScript default parameters are cleaner because the default is declared directly in the signature.
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
# Return Type `string[]`
|
||||
|
||||
TypeScript can declare exactly what a function returns.
|
||||
|
||||
## Example
|
||||
|
||||
```ts
|
||||
function buildWeeklyDownloadPeriods(...): string[] {
|
||||
return ['2026-03-23T23:00:00.000Z/2026-03-30T22:00:00.000Z'];
|
||||
}
|
||||
```
|
||||
|
||||
## Meaning
|
||||
|
||||
- `string[]` means "array of strings".
|
||||
- Each array item must be a `string`.
|
||||
|
||||
## Python comparison
|
||||
|
||||
```py
|
||||
from typing import List
|
||||
|
||||
def build_weekly_download_periods(...) -> List[str]:
|
||||
return ['a/b']
|
||||
```
|
||||
|
||||
TypeScript enforces this statically, so returning non-strings will be flagged by the type checker.
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
# Array `slice` and Indexing
|
||||
|
||||
Your snippet uses `slice` and index-based access to create weekly intervals.
|
||||
|
||||
## `slice(0, -1)`
|
||||
|
||||
```ts
|
||||
const periodStarts = alignedStarts.slice(0, -1);
|
||||
```
|
||||
|
||||
- Start at index `0`.
|
||||
- Stop before the last item (`-1` means from the end).
|
||||
- Useful when each `start` needs a following `end` item.
|
||||
|
||||
## Index access
|
||||
|
||||
```ts
|
||||
const end = alignedStarts[index + 1];
|
||||
```
|
||||
|
||||
- Gets the next boundary after the current `start`.
|
||||
|
||||
## Python comparison
|
||||
|
||||
```py
|
||||
period_starts = aligned_starts[:-1]
|
||||
end = aligned_starts[index + 1]
|
||||
```
|
||||
|
||||
This is the same concept as Python slicing and list indexing.
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
# Timestamps with `getTime()`
|
||||
|
||||
`Date.getTime()` returns a timestamp in milliseconds since Unix epoch.
|
||||
|
||||
## Example
|
||||
|
||||
```ts
|
||||
const startTime = start.getTime();
|
||||
```
|
||||
|
||||
## Why this is useful
|
||||
|
||||
Numeric timestamps are easy to compare:
|
||||
|
||||
```ts
|
||||
startTime >= rangeStart
|
||||
startTime <= rangeEnd
|
||||
```
|
||||
|
||||
Comparing numbers is usually simpler and safer than comparing date strings directly.
|
||||
|
||||
## Python comparison
|
||||
|
||||
```py
|
||||
start_ts_ms = int(start_dt.timestamp() * 1000)
|
||||
```
|
||||
|
||||
Both represent an absolute moment in time.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Guard Clauses and Range Validation
|
||||
|
||||
A guard clause exits early when input is invalid.
|
||||
|
||||
## Example from your snippet
|
||||
|
||||
```ts
|
||||
if (rangeStart !== undefined && rangeEnd !== undefined && rangeStart > rangeEnd) {
|
||||
return [];
|
||||
}
|
||||
```
|
||||
|
||||
## Why this is good
|
||||
|
||||
- Fails fast.
|
||||
- Prevents harder-to-debug logic later.
|
||||
- Keeps the main flow cleaner.
|
||||
|
||||
## Operator notes
|
||||
|
||||
- `!==`: strict "not equal" comparison.
|
||||
- `&&`: logical AND (all conditions must be true).
|
||||
- `>`: greater-than comparison.
|
||||
|
||||
## Python comparison
|
||||
|
||||
```py
|
||||
if range_start is not None and range_end is not None and range_start > range_end:
|
||||
return []
|
||||
```
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
# `flatMap` as Filter + Map Pattern
|
||||
|
||||
`flatMap` can both remove items and transform remaining items.
|
||||
|
||||
## Pattern in your snippet
|
||||
|
||||
```ts
|
||||
return periodStarts.flatMap((start, index) => {
|
||||
if (!matchesRange) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return `${start.toISOString()}/${end.toISOString()}`;
|
||||
});
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
- Return `[]` to drop an element.
|
||||
- Return a value to keep/transform it.
|
||||
- `flatMap` flattens one level automatically.
|
||||
|
||||
## Equivalent with `filter` + `map`
|
||||
|
||||
```ts
|
||||
return periodStarts
|
||||
.filter((start) => isInRange(start))
|
||||
.map((start, index) => makeInterval(start, index));
|
||||
```
|
||||
|
||||
## Python comparison
|
||||
|
||||
Usually done as separate steps:
|
||||
|
||||
```py
|
||||
filtered = [s for s in period_starts if in_range(s)]
|
||||
result = [make_interval(s, i) for i, s in enumerate(filtered)]
|
||||
```
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# ISO Strings and Template Literals
|
||||
|
||||
Your code builds interval strings using `toISOString()` and a template literal.
|
||||
|
||||
## Example
|
||||
|
||||
```ts
|
||||
const interval = `${start.toISOString()}/${end.toISOString()}`;
|
||||
```
|
||||
|
||||
## Why this format is good
|
||||
|
||||
- ISO format is unambiguous.
|
||||
- Easy for backend APIs to parse.
|
||||
- Includes timezone info (`Z` for UTC).
|
||||
|
||||
Example value:
|
||||
|
||||
```text
|
||||
2026-03-23T23:00:00.000Z/2026-03-30T22:00:00.000Z
|
||||
```
|
||||
|
||||
This describes one weekly period as `start/end`.
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
# Understanding `alignedStarts`
|
||||
|
||||
`alignedStarts` is an array of date boundaries that match your backend schedule rule.
|
||||
|
||||
## Concept
|
||||
|
||||
```ts
|
||||
const alignedStarts: Date[] = [];
|
||||
```
|
||||
|
||||
Each item is a valid period boundary (for example Monday 00:00 in backend-local schedule terms).
|
||||
|
||||
Later, you form intervals by pairing adjacent items:
|
||||
|
||||
```ts
|
||||
const start = alignedStarts[index];
|
||||
const end = alignedStarts[index + 1];
|
||||
```
|
||||
|
||||
So if `alignedStarts` has `N` items, you can make up to `N-1` intervals.
|
||||
|
||||
## Why this is useful
|
||||
|
||||
- Keeps schedule boundaries consistent.
|
||||
- Makes interval generation deterministic.
|
||||
- Handles DST-safe boundaries when generated correctly.
|
||||
Reference in New Issue
Block a user