Differences
This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| note:tue_jun_17_2025 [2025/06/17 03:40] – created lingao | note:tue_jun_17_2025 [2025/06/17 13:00] (current) – [dokuwiki docker upgrade] lingao | ||
|---|---|---|---|
| Line 3: | Line 3: | ||
| typehero | typehero | ||
| - | <codeprism | + | <code ts> |
| declare const config: Chainable | declare const config: Chainable | ||
| Line 20: | Line 20: | ||
| } | } | ||
| } | } | ||
| - | </codeprism> | + | </code> |
| ===== Type Argument Inference in TypeScript ===== | ===== Type Argument Inference in TypeScript ===== | ||
| - | ==== Goal ==== | + | ==== Goal: Understand how TypeScript infers type arguments |
| - | Understand how TypeScript infers type arguments | + | |
| - | ==== Step 1: Learn the Basics ==== | ||
| - | * **Read Documentation**: | ||
| - | - [[https:// | ||
| - | - [[https:// | ||
| - | * **Watch Tutorial**: | ||
| - | - [[https:// | ||
| - | * **Take Notes**: | ||
| - | - Define: What is **type argument inference**? | ||
| - | ==== Step 2: Experiment in TypeScript Playground ==== | + | <code typescript> |
| - | * Open [[https:// | + | type Chainable<T = {}> = { |
| - | | + | |
| - | function identity<T>(arg: T): T { return arg; } | + | |
| - | const a = identity(" | + | |
| - | const b = identity(42); | + | |
| - | | + | |
| - | * Modify the function to see when inference **fails** | + | |
| - | + | ||
| - | ==== Step 3: Real-World Examples ==== | + | |
| - | * **Analyze Open-Source Code**: | + | |
| - | - Search for generics in libraries like [[https:// | + | |
| - | - Example: `get<T = any>(url: string): Promise<T>`. How does inference work here? | + | |
| - | * **Write Your Own Generic Function**: | + | |
| - | < | + | |
| - | function mapArray< | + | |
| - | | + | |
| } | } | ||
| - | const nums = [1, 2, 3]; | + | </code> |
| - | const doubled = mapArray(nums, | + | |
| - | | + | |
| - | ==== Step 4: Edge Cases & Explicit Types ==== | + | Why K is Inferred, |
| - | * **When Inference Fails**: | + | |
| - | < | + | |
| - | function merge<T, U>(a: T, b: U): T & U { return { ...a, ...b }; } | + | |
| - | const merged = merge({ name: " | + | |
| - | const badMerge = merge({ name: " | + | |
| - | </ | + | |
| - | * **Explicit Type Passing**: | + | |
| - | < | + | |
| - | const explicit = merge<{ name: string }, { age: number }>( | + | |
| - | { name: " | + | |
| - | { age: 30 } | + | |
| - | ); | + | |
| - | </ | + | |
| - | + | ||
| - | ==== Step 5: Build a Mini-Project ==== | + | |
| - | * **Generic `fetchData` Wrapper**: | + | |
| - | < | + | |
| - | async function fetchData< | + | |
| - | const res = await fetch(url); | + | |
| - | return res.json(); | + | |
| - | } | + | |
| - | interface User { id: number; name: string; } | + | |
| - | const user = await fetchData< | + | |
| - | </ | + | |
| - | * Test with APIs like [[https:// | + | |
| - | + | ||
| - | ==== Step 6: Advanced Topics ==== | + | |
| - | * **Default Type Parameters**: | + | |
| - | < | + | |
| - | function createArray< | + | |
| - | return Array(length).fill(value); | + | |
| - | } | + | |
| - | const strArray = createArray(3, | + | |
| - | </ | + | |
| - | * **Constraints & Inference**: | + | |
| - | < | + | |
| - | function longest< | + | |
| - | return a.length >= b.length | + | |
| - | } | + | |
| - | const longer = longest(" | + | |
| - | </ | + | |
| - | + | ||
| - | ==== Final Challenge ==== | + | |
| - | * Refactor a project to use inference where possible. | + | |
| - | * Explain the concept in a post (teaching reinforces learning). | + | |
| - | + | ||
| - | ==== Key Takeaways ==== | + | |
| - | * TypeScript infers types **when possible** (e.g., from arguments). | + | |
| - | * Explicit types are needed **when inference fails**. | + | |
| - | * Test in the [[https:// | + | |
| - | + | ||
| - | ==== Resources ==== | + | |
| - | * [[https:// | + | |
| - | * [[https:// | + | |
| + | TypeScript' | ||
| + | <code typescript> | ||
| + | // When you write: | ||
| + | config.option(' | ||
| + | // TypeScript thinks: | ||
| + | // - Receiver type: Chainable< | ||
| + | // - First argument: ' | ||
| + | // → Must infer K = ' | ||
| + | // - Second argument: ' | ||
| + | // → Must infer V = ' | ||
| + | </ | ||
| + | What If T Were Also a Type Parameter? | ||
| + | If we hypothetically made T also inferrable, it would create ambiguity: | ||
| + | <code typescript> | ||
| + | // Hypothetical (problematic) design: | ||
| + | type BadChainable = { | ||
| + | option< | ||
| + | key: Exclude< | ||
| + | value: V | ||
| + | ): Chainable< | ||
| + | } | ||
| + | // How would TypeScript know what T should be? | ||
| + | // There would be no way to infer T from the arguments! | ||
| + | </ | ||
| + | ===== The NoInfer Utility Type ===== | ||
| + | <code lang=typescript el=true > | ||
| + | function createStreetLight< | ||
| + | // ... | ||
| + | } | ||
| + | createStreetLight([" | ||
| + | // ^^^^^ defaultColor?: | ||
| + | // But I don't want blue, because blue is not the color in colors. | ||
| + | // So | ||
| + | function createStreetLight< | ||
| + | // ... | ||
| + | } | ||
| + | createStreetLight([" | ||
| + | // ~~~~~~ | ||
| + | // error! | ||
| + | // Argument of type '" | ||
| + | </ | ||
| + | ===== dokuwiki docker upgrade ===== | ||
| + | <code lang=bash> | ||
| + | tar -czvf " | ||
| + | mv *config.tar.gz ./backup | ||
| + | docker compose down && docker compose pull && docker compose up -d | ||
| + | </ | ||
| + | ===== Tuple Map ===== | ||
| + | we can use mapped types for creating tuples. It's because tuple properties are indexes. | ||
| + | <code typescript> | ||
| + | type A<T extends unknown[]> | ||
| + | [P in keyof T] : T[P] | ||
| + | } | ||
| + | type a = A< | ||
| + | // ^ type a = [1, 2, 3] | ||
| + | </ | ||