Series · 42 phần
TypeScript Engineering — từ Type System đến Production
Lộ trình tiếng Việt 42 phần gom toàn bộ nội dung TypeScript của blog vào một series duy nhất. Chặng Production Engineering dựng mental model về soundness, strict config, narrowing và inference; đào sâu conditional types, infer, mapped types, tuple, template-literal DSL, recursion và union algebra; rồi đưa chúng qua runtime boundary, async contract, module, declaration, kiến trúc, monorepo, migration và capstone typed SDK. Chặng Type Challenges gồm 12 bài luyện type-level programming từ năm khối nền tảng tới parser, state machine và typed path utility. Chặng cuối áp dụng TypeScript vào 10 design pattern thực chiến như Factory, Builder, Strategy, Observer, Decorator, Adapter, Command, State, Proxy và Dependency Injection.
01 Nền tảng để đọc compiler
Nắm giới hạn soundness, strictness, narrowing và generic inference trước khi viết type-level code.
-
Hiểu TypeScript thực sự chứng minh gì: structural typing, excess-property check, any/unknown/never, variance, array covariance và các lỗ hổng soundness cần cô lập.
-
Thiết kế tsconfig theo runtime và toolchain, bật strict flags có chủ đích, hiểu target/lib/module, noEmit, isolatedModules và những thay đổi quan trọng của TypeScript 6.
-
Dùng control-flow analysis, type predicate, assertion function và discriminated union để biến trạng thái bất hợp lệ thành không thể biểu diễn.
-
Thiết kế generic API để compiler suy luận từ input, dùng constraints, const type parameters, overload đúng chỗ và tránh conditional type làm public API khó hiểu.
02 Type-level engineering chuyên sâu
Dùng conditional types, infer, mapped types, tuple, template literal, recursion và union algebra để xây API có kiểm soát.
-
Dùng conditional type như type function: kiểm soát distribution, never/any/unknown, Extract/Exclude, giữ correlation cho event và SDK mà không làm type checker quá tải.
-
Làm chủ infer từ ReturnType tới candidate resolution, variadic tuple, constrained infer, recursive extraction và các contract router, i18n, state machine trong production.
-
Làm chủ mapped type nâng cao: homomorphic mapping, modifiers, key remapping/filtering, string-number-symbol keys và API sinh từ schema mà vẫn giữ contract dễ kiểm thử.
-
Dùng variadic và labeled tuples để giữ nguyên parameter list qua partial application, Promise concurrency, constructor wrapper và function pipeline mà không rơi về any[].
-
Biến route, event topic và i18n placeholder thành contract có type bằng template literals, recursive infer và constrained infer—đồng thời giữ runtime parser cùng một grammar.
-
Viết recursive type có điểm dừng, depth fuel và seen set; chẩn đoán TS2589, đo chi phí bằng diagnostics/trace, và biết lúc nào nên chuyển sang code generation.
-
Dùng distributive conditional, mapped union và union-to-intersection để giữ correlation cho event/job API; tránh bẫy keyof union, union ordering và generic explosion.
-
Thiết kế inference như public contract: contextual typing, candidate collection, literal preservation, partial inference, NoInfer, higher-order API và type tests cho config, query, builder.
03 Contract chạy được ở production
Nối compile-time model với dữ liệu runtime, lỗi, bất đồng bộ, module và public package.
-
Biến unknown từ API, storage và env thành domain value đáng tin: parse at the edge, schema evolution, branded types, DTO mapping và contract versioning.
-
Thiết kế lỗi và async flow có kiểu: unknown catch, Result, AbortSignal, timeout, retry, Promise concurrency và idempotency thay vì Promise<any>.
-
Hiểu runtime module trước compiler: NodeNext vs Bundler, package type/exports, import type, file extension, dual-package hazard và cách debug resolution.
-
Ship package TypeScript đáng tin: declaration emit, exports map, public type surface, type tests, API Extractor mindset và semver cho thay đổi inference.
04 Scale codebase và tổ chức
Thiết kế boundary, build graph, type performance, migration, governance và release gate ở cấp Staff.
-
Dùng TypeScript để bảo vệ dependency direction: domain, ports/adapters, capability interfaces, composition root, anti-corruption layer và compile-time architecture tests.
-
Scale TypeScript bằng build graph rõ: composite projects, tsc -b, declaration boundaries, incremental build, diagnostics và cách giảm type instantiation cost.
-
Kết hợp runtime, type, artifact và consumer tests; migrate legacy theo boundary, kiểm Type SemVer, nâng compiler bằng canary và vận hành governance không nghẽn delivery.
-
Capstone ghép toàn series: xây SDK HTTP có runtime validation, branded IDs, typed errors, cancellation, ESM exports, declaration tests, project references và release gates.
05 Type Challenges — từ nền tảng đến type wizard
Luyện mapped type, conditional type, infer, recursion, union, template literal, type-level arithmetic và parser qua challenge có lời giải.
-
A bilingual walkthrough of classic type-challenges (easy → hard): Pick, Readonly, Exclude, Awaited, Omit, DeepReadonly, Permutation, Union to Intersection, CamelCase — each with a toggle-to-reveal answer and a detailed explanation.
-
Part 2: master the mapped type. Rebuild Partial, Required, Mutable, Readonly 2, PartialByKeys, Merge and ReplaceKeys; add and remove the readonly/? modifiers; and key-remap with as — each with a toggle-to-reveal answer.
-
Part 3: the A extends B ? X : Y engine. Build If, IsNever, IsUnion and AnyOf, nail the distributive rule (and switch it off with [T]), and decode the Equal gadget behind every test — each with a toggle-to-reveal answer.
-
Part 4: capture pieces of a type with infer. Rebuild Parameters, Last and Pop, append arguments to functions, and learn constrained infer (infer N extends number) to parse numbers from strings — each with a toggle-to-reveal answer.
-
Part 5: peel one element off and loop. Build Push, Unshift, Reverse, Includes, Flatten and Join with recursion over tuples, learn the accumulator pattern, and understand the recursion depth limit — each with a toggle-to-reveal answer.
-
Part 6: unions are not tuples. Turn a string into a union, recap distribution, extract the last member of a union, and build the famous UnionToTuple with the contravariance gadget — each with a toggle-to-reveal answer and explanation.
-
Part 7: string math at the type level. Build Trim, Replace, ReplaceAll, StartsWith/EndsWith and LengthOfString with template-literal pattern matching and recursion — each with a toggle-to-reveal answer and a step-by-step explanation.
-
Part 8: TypeScript has no + for numbers, so we count with tuple lengths. Build BuildTuple, Add, Subtract, GreaterThan and Fibonacci using the accumulator and tuple-length tricks — each with a toggle-to-reveal answer and explanation.
-
Part 9: type utilities from real libraries. Split objects by required vs optional keys with GetRequired, RequiredKeys and OptionalKeys, then build a fluent, type-safe Chainable builder — each with a toggle-to-reveal answer.
-
Part 10: parse strings at the type level. Convert camelCase to kebab-case, fold a tuple into a nested object, and build a real printf format parser that walks a string as a state machine — each with a toggle-to-reveal answer.
-
Part 11: the hardest entries, taken slowly. Build Currying, a dotted-path Get, and IsPalindrome by composing patterns from the whole series — proof that extreme types are just familiar tricks stacked. With toggle-to-reveal answers.
-
Part 12: turn the series into a real, fully-typed deep-get utility with autocompleted paths, then master the meta-skills — debugging types, recursion and performance limits, a one-page pattern cheat sheet, and a practice plan.
06 Design Patterns trong TypeScript
Áp dụng các pattern tạo object, thay đổi hành vi, giao tiếp, state và dependency boundary vào code TypeScript thực tế.
-
When (and when not) to share a single instance: the Singleton pattern, why ESM modules are already singletons, lazy init, the testability trap, and typed implementations — with exercises.
-
Centralize object creation: factory functions over `new`, discriminated-union driven factories, the Abstract Factory for families of related objects, and where this beats classes in TypeScript.
-
Construct complex objects step by step: fluent method chaining, immutable builders, the type-safe staged (phantom-type) builder that makes illegal states unrepresentable, and when an options object is enough.
-
Swap an algorithm at runtime without touching its caller: the Strategy pattern, why a map of functions is the idiomatic TS form, replacing sprawling if/switch, and injecting behavior for testability.
-
Decouple "something changed" from "who reacts": the Observer pattern, a fully typed event emitter, the platform EventTarget, Pub/Sub via an event bus, and how signals/reactivity build on the same idea.
-
Add behavior without touching the original: the Decorator pattern via higher-order functions, wrapping a service to add caching/logging/retry, the middleware chain, and how TS decorators (and the new standard) compare.
-
Tame third-party and legacy code: the Adapter that makes an incompatible API fit your interface, the Facade that hides a messy subsystem behind one entry point, and the anti-corruption layer that keeps vendor types out of your domain.
-
Turn actions into data: the Command pattern for dispatch, queues, and undo/redo, the Memento for snapshotting state, and how reducers (Redux-style) are commands in disguise.
-
Make impossible states impossible: the State pattern, modeling UI/lifecycle with a finite state machine, type-safe transitions via discriminated unions, and why this kills "loading && error" bugs.
-
Control access and wire your app for testability: the JS Proxy for reactivity/validation/lazy loading, Dependency Injection and Inversion of Control, the composition root, and choosing constructor injection over service-locator.