Skip to content

Commit 77ea00d

Browse files
committed
Add TypeScript expert track
1 parent 31e5f2a commit 77ea00d

34 files changed

Lines changed: 1295 additions & 38 deletions

File tree

LANGUAGE_PARITY_MATRIX.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
This matrix tracks module and checkpoint parity across C++, C#, Go, Python, and TypeScript.
44

55
- Canonical order is defined by the C++ track.
6-
- C++, C#, Go, and Python now reach module and checkpoint parity through `04-expert`.
7-
- TypeScript is the newest incremental track with `01-foundations`, `02-core`, and `03-advanced` implemented first.
6+
- C++, C#, Go, Python, and TypeScript now reach module and checkpoint parity through `04-expert`.
87
- Status labels:
98
- `Done`: module implemented with example, exercises, and README.
109
- `Planned`: module not implemented yet, already queued in order.
@@ -47,7 +46,7 @@ Current parity progress in non-C++ tracks:
4746
- C#: `5/5` modules complete in `03-advanced`, `5/5` in `04-expert`
4847
- Go: `5/5` modules complete in `03-advanced`, `5/5` in `04-expert`
4948
- Python: `5/5` modules complete in `03-advanced`, `5/5` in `04-expert`
50-
- TypeScript: `5/5` modules complete in `03-advanced`; `04-expert` planned next
49+
- TypeScript: `5/5` modules complete in `03-advanced`, `5/5` in `04-expert`
5150

5251
### Advanced (`03-advanced`) - Current Expansion Queue
5352

@@ -59,17 +58,17 @@ Current parity progress in non-C++ tracks:
5958
| 4 | inheritance-and-polymorphism | Done | Done | Done | Done | Done |
6059
| 5 | templates-basics | Done | Done | Done | Done | Done |
6160

62-
`04-expert` projects and assessments are now implemented across C#, Go, and Python.
61+
`04-expert` projects and assessments are now implemented across all active non-C++ tracks.
6362

6463
### Expert (`04-expert`)
6564

6665
| Order | Module | C++ | C# | Go | Python | TypeScript |
6766
| --- | --- | --- | --- | --- | --- | --- |
68-
| 1 | memory-management-and-raii | Done | Done | Done | Done | Planned |
69-
| 2 | smart-pointers-in-depth | Done | Done | Done | Done | Planned |
70-
| 3 | concurrency-basics | Done | Done | Done | Done | Planned |
71-
| 4 | performance-and-profiling-basics | Done | Done | Done | Done | Planned |
72-
| 5 | modularization-and-build-structure | Done | Done | Done | Done | Planned |
67+
| 1 | memory-management-and-raii | Done | Done | Done | Done | Done |
68+
| 2 | smart-pointers-in-depth | Done | Done | Done | Done | Done |
69+
| 3 | concurrency-basics | Done | Done | Done | Done | Done |
70+
| 4 | performance-and-profiling-basics | Done | Done | Done | Done | Done |
71+
| 5 | modularization-and-build-structure | Done | Done | Done | Done | Done |
7372

7473
## Checkpoint Parity
7574

@@ -85,7 +84,7 @@ Status labels:
8584
| 01-foundations | Done | Done | Done | Done | Done |
8685
| 02-core | Done | Done | Done | Done | Done |
8786
| 03-advanced | Done | Done | Done | Done | Done |
88-
| 04-expert | Done | Done | Done | Done | Planned |
87+
| 04-expert | Done | Done | Done | Done | Done |
8988

9089
### Assessments
9190

@@ -94,4 +93,4 @@ Status labels:
9493
| 01-foundations | Done | Done | Done | Done | Done |
9594
| 02-core | Done | Done | Done | Done | Done |
9695
| 03-advanced | Done | Done | Done | Done | Done |
97-
| 04-expert | Done | Done | Done | Done | Planned |
96+
| 04-expert | Done | Done | Done | Done | Done |

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ If you only want to learn one track, follow that track README first because lang
5454
| C# | 01-foundations, 02-core, 03-advanced, 04-expert | 8/8 foundations modules, 6/6 core modules, 5/5 advanced modules, 5/5 expert modules, 4/4 projects, 4/4 assessments | Module and checkpoint parity complete through expert |
5555
| Go | 01-foundations, 02-core, 03-advanced, 04-expert | 8/8 foundations modules, 6/6 core modules, 5/5 advanced modules, 5/5 expert modules, 4/4 projects, 4/4 assessments | Module and checkpoint parity complete through expert |
5656
| Python | 01-foundations, 02-core, 03-advanced, 04-expert | 8/8 foundations modules, 6/6 core modules, 5/5 advanced modules, 5/5 expert modules, 4/4 projects, 4/4 assessments | Module and checkpoint parity complete through expert |
57-
| TypeScript | 01-foundations, 02-core, 03-advanced | 8/8 foundations modules, 6/6 core modules, 5/5 advanced modules, 3/4 projects, 3/4 assessments | Foundations, core, and advanced complete; expert planned |
57+
| TypeScript | 01-foundations, 02-core, 03-advanced, 04-expert | 8/8 foundations modules, 6/6 core modules, 5/5 advanced modules, 5/5 expert modules, 4/4 projects, 4/4 assessments | Module and checkpoint parity complete through expert |
5858

5959
Parity planning reference: [LANGUAGE_PARITY_MATRIX.md](LANGUAGE_PARITY_MATRIX.md)
6060

@@ -171,7 +171,7 @@ GitHub Actions validates links, README structure, module completeness, checkpoin
171171

172172
The public PowerShell and Bash scripts remain the supported entrypoints, but they now delegate to a shared Python automation core under `scripts/automation.py` backed by `scripts/automation_manifest.json`.
173173

174-
The multi-language smoke scripts also compile standalone C# exercises by generating temporary validation projects during the check and compile TypeScript foundations programs before executing their smoke targets.
174+
The multi-language smoke scripts also compile standalone C# exercises by generating temporary validation projects during the check and compile TypeScript programs before executing their smoke targets.
175175

176176
## Contributing
177177

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# TypeScript 04 Expert
2+
3+
This level adapts expert topics to TypeScript's runtime model: explicit cleanup, reference identity, async concurrency, performance measurement, and modular structure.
4+
5+
## Learning Metadata
6+
7+
- Difficulty: Advanced.
8+
- Estimated Time: 4-6 hours across modules, project, and assessment.
9+
- Prerequisites: Completion of `03-advanced` plus its project or assessment checkpoint.
10+
- Study Strategy: Work through the modules in order, then the capstone, then the assessment, and compare which expert ideas map directly from C++ and which need a TypeScript-specific interpretation.
11+
12+
## Module Order
13+
14+
1. [memory-management-and-raii](./memory-management-and-raii/README.md)
15+
2. [smart-pointers-in-depth](./smart-pointers-in-depth/README.md)
16+
3. [concurrency-basics](./concurrency-basics/README.md)
17+
4. [performance-and-profiling-basics](./performance-and-profiling-basics/README.md)
18+
5. [modularization-and-build-structure](./modularization-and-build-structure/README.md)
19+
20+
Track progress in [../CHECKLIST.md](../CHECKLIST.md).
21+
22+
## Study Tip
23+
24+
Treat this level as a translation exercise: TypeScript does not have RAII or move semantics in the C++ sense, so focus on explicit cleanup, reference behavior, and event-loop concurrency instead of forcing one-to-one vocabulary matches.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Concurrency Basics
2+
3+
This module introduces TypeScript concurrency through async tasks, `Promise.all`, and work coordination on the event loop.
4+
5+
## Learning Metadata
6+
7+
- Difficulty: Advanced.
8+
- Estimated Time: 45-60 minutes.
9+
- Prerequisites: `02-core/algorithms-basics` and `03-advanced/templates-basics`.
10+
- Cross-Language Lens: Compare thread-based concurrency in C++ or Go with TypeScript's event-loop concurrency, where tasks overlap without shared-memory threads by default.
11+
12+
## Quick Run
13+
14+
~~~bash
15+
npm run build:typescript
16+
node build/typescript/04-expert/concurrency-basics/example/main.js
17+
~~~
18+
19+
## Topics Covered
20+
21+
- Launching independent async tasks.
22+
- Preserving result order with `Promise.all`.
23+
- Limiting concurrency with a worker-pool helper.
24+
- Separating task coordination from task logic.
25+
26+
## Common Pitfalls
27+
28+
- Confusing concurrency with parallel CPU work.
29+
- Awaiting inside a loop when independent work could overlap.
30+
- Mutating shared arrays in confusing ways instead of returning results.
31+
- Ignoring task failures inside a larger concurrent batch.
32+
33+
## Exercise Focus
34+
35+
- exercises/01.ts: fetch several async results and preserve display order.
36+
- exercises/02.ts: process jobs with a maximum of two active workers.
37+
38+
### Exercise Specs
39+
40+
1. exercises/01.ts
41+
- Input: none.
42+
- Output: completed task results in the original request order.
43+
- Edge cases: mixed delays; one task finishing earlier than the first request.
44+
45+
2. exercises/02.ts
46+
- Input: none.
47+
- Output: worker start/finish logs plus a final ordered summary.
48+
- Edge cases: fewer jobs than workers; an empty job list.
49+
50+
## Checkpoint
51+
52+
- [ ] I can explain how `Promise.all` overlaps async work.
53+
- [ ] I can preserve deterministic output even when completion order varies.
54+
- [ ] I can limit concurrency without rewriting the task itself.
55+
- [ ] I completed exercises/01.ts.
56+
- [ ] I completed exercises/02.ts.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { setTimeout as delay } from "node:timers/promises";
2+
3+
type JobResult = {
4+
name: string;
5+
score: number;
6+
};
7+
8+
async function loadJob(
9+
name: string,
10+
waitMs: number,
11+
score: number,
12+
): Promise<JobResult> {
13+
await delay(waitMs);
14+
return { name, score };
15+
}
16+
17+
async function main(): Promise<void> {
18+
// Promise.all keeps the output order tied to the request order.
19+
const results = await Promise.all([
20+
loadJob("load", 25, 3),
21+
loadJob("validate", 10, 5),
22+
loadJob("save", 15, 4),
23+
]);
24+
25+
const total = results.reduce((sum, result) => sum + result.score, 0);
26+
27+
console.log(`Completed ${results.length} concurrent jobs.`);
28+
for (const result of results) {
29+
console.log(`- ${result.name}: ${result.score}`);
30+
}
31+
console.log(`Total value: ${total}`);
32+
}
33+
34+
main().catch((error: unknown) => {
35+
if (error instanceof Error) {
36+
console.error(error.message);
37+
} else {
38+
console.error("Unknown error");
39+
}
40+
process.exitCode = 1;
41+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { setTimeout as delay } from "node:timers/promises";
2+
3+
async function fetchLabel(label: string, waitMs: number): Promise<string> {
4+
await delay(waitMs);
5+
return `${label} ready`;
6+
}
7+
8+
async function main(): Promise<void> {
9+
const labels = await Promise.all([
10+
fetchLabel("alpha", 20),
11+
fetchLabel("beta", 5),
12+
fetchLabel("gamma", 12),
13+
]);
14+
15+
for (const label of labels) {
16+
console.log(label);
17+
}
18+
}
19+
20+
main().catch((error: unknown) => {
21+
if (error instanceof Error) {
22+
console.error(error.message);
23+
}
24+
process.exitCode = 1;
25+
});
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { setTimeout as delay } from "node:timers/promises";
2+
3+
async function runWithLimit<T>(
4+
values: T[],
5+
limit: number,
6+
worker: (value: T) => Promise<string>,
7+
): Promise<string[]> {
8+
const results = new Array<string>(values.length);
9+
let nextIndex = 0;
10+
11+
async function runWorker(): Promise<void> {
12+
while (nextIndex < values.length) {
13+
const currentIndex = nextIndex;
14+
nextIndex += 1;
15+
results[currentIndex] = await worker(values[currentIndex]!);
16+
}
17+
}
18+
19+
const runners = Array.from({ length: Math.min(limit, values.length) }, () =>
20+
runWorker(),
21+
);
22+
await Promise.all(runners);
23+
return results;
24+
}
25+
26+
async function main(): Promise<void> {
27+
const jobs = [30, 10, 20, 5];
28+
const results = await runWithLimit(jobs, 2, async (waitMs) => {
29+
await delay(waitMs);
30+
return `finished ${waitMs}`;
31+
});
32+
33+
for (const result of results) {
34+
console.log(result);
35+
}
36+
}
37+
38+
main().catch((error: unknown) => {
39+
if (error instanceof Error) {
40+
console.error(error.message);
41+
}
42+
process.exitCode = 1;
43+
});
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Memory Management and RAII
2+
3+
This module adapts RAII to TypeScript by focusing on explicit cleanup, `try/finally`, and disposable-style helpers.
4+
5+
## Learning Metadata
6+
7+
- Difficulty: Advanced.
8+
- Estimated Time: 30-45 minutes.
9+
- Prerequisites: `03-advanced/constructors-and-invariants` and `02-core/error-handling-and-defensive-programming`.
10+
- Cross-Language Lens: Compare C++ destructor-driven cleanup with TypeScript's explicit `close` methods and `try/finally` scopes.
11+
12+
## Quick Run
13+
14+
~~~bash
15+
npm run build:typescript
16+
node build/typescript/04-expert/memory-management-and-raii/example/main.js
17+
~~~
18+
19+
## Topics Covered
20+
21+
- Explicit cleanup through `close`.
22+
- Wrapping resource usage in helper scopes.
23+
- Guarding against use-after-close bugs.
24+
- Separating resource lifetime from business logic.
25+
26+
## Common Pitfalls
27+
28+
- Assuming garbage collection will close files or sockets for you.
29+
- Forgetting to close a resource on the error path.
30+
- Reusing a closed resource because the object reference still exists.
31+
- Mixing cleanup logic into unrelated application code.
32+
33+
## Exercise Focus
34+
35+
- exercises/01.ts: use `try/finally` to close a temporary resource safely.
36+
- exercises/02.ts: enforce closed-state guardrails in a reusable session object.
37+
38+
### Exercise Specs
39+
40+
1. exercises/01.ts
41+
- Input: none.
42+
- Output: setup, work, and cleanup messages in the correct order.
43+
- Edge cases: cleanup must still happen after a simulated failure.
44+
45+
2. exercises/02.ts
46+
- Input: none.
47+
- Output: session logs before closing, after closing, and a guarded error message.
48+
- Edge cases: repeated close calls; operations attempted after close.
49+
50+
## Checkpoint
51+
52+
- [ ] I can explain why garbage collection does not replace explicit cleanup.
53+
- [ ] I can use `try/finally` to guarantee cleanup.
54+
- [ ] I can guard a resource from use-after-close mistakes.
55+
- [ ] I completed exercises/01.ts.
56+
- [ ] I completed exercises/02.ts.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
class FakeFile {
2+
private closed = false;
3+
4+
constructor(readonly name: string) {
5+
console.log(`Opening ${name}`);
6+
}
7+
8+
writeLine(line: string): void {
9+
this.ensureOpen();
10+
console.log(`writing: ${line}`);
11+
}
12+
13+
close(): void {
14+
if (!this.closed) {
15+
console.log(`Closing ${this.name}`);
16+
this.closed = true;
17+
}
18+
}
19+
20+
isClosed(): boolean {
21+
return this.closed;
22+
}
23+
24+
private ensureOpen(): void {
25+
if (this.closed) {
26+
throw new Error("Resource already closed.");
27+
}
28+
}
29+
}
30+
31+
function usingResource<T extends { close(): void }, TResult>(
32+
resource: T,
33+
work: (resource: T) => TResult,
34+
): TResult {
35+
try {
36+
return work(resource);
37+
} finally {
38+
resource.close();
39+
}
40+
}
41+
42+
function main(): void {
43+
// Intent: make cleanup explicit even though the language has garbage collection.
44+
const report = new FakeFile("report.txt");
45+
46+
usingResource(report, (handle) => {
47+
handle.writeLine("header");
48+
handle.writeLine("totals");
49+
});
50+
51+
console.log(`Closed after scope: ${report.isClosed()}`);
52+
}
53+
54+
main();
55+
56+
export {};

0 commit comments

Comments
 (0)