note:tue_jun_17_2025

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
note:tue_jun_17_2025 [2025/06/17 03:40] – created lingaonote:tue_jun_17_2025 [2025/06/17 13:00] (current) – [dokuwiki docker upgrade] lingao
Line 3: Line 3:
 typehero typehero
  
-<codeprism ts>+<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 ====   +==== GoalUnderstand how TypeScript infers type arguments ====  
-Understand how TypeScript infers type arguments in generics and use it to write cleaner code.  +
  
-==== Step 1: Learn the Basics ====   
-  * **Read Documentation**:   
-    - [[https://www.typescriptlang.org/docs/handbook/2/generics.html|TypeScript Generics]] (focus on "Type Argument Inference").   
-    - [[https://www.typescriptlang.org/docs/handbook/type-inference.html|Type Inference in Generics]].   
-  * **Watch Tutorial**:   
-    - [[https://youtu.be/nViEqpgwxHE|TypeScript Generics Explained]] (stop at 8:50 for inference).   
-  * **Take Notes**:   
-    - Define: What is **type argument inference**? When does TypeScript infer types automatically?   
  
-==== Step 2: Experiment in TypeScript Playground ====   +<code typescript> 
-  * Open [[https://www.typescriptlang.org/play|TypeScript Playground]] and test:   +type Chainable<T {}{ 
-    <codeprism typescript> +  option<K extends string, V>(keyExclude<K, keyof T>, valueV): Chainable<Omit<T, K& {[P in K]: V}
-function identity<T>(arg: T): T return arg; } +  get(): T
-const a identity("hello"); // Type inferred as `string`   +
-const b = identity(42);      // Type inferred as `number`   +
-    </codeprism  +
-  * Modify the function to see when inference **fails** (e.g., add `extends` constraints).   +
- +
-==== Step 3Real-World Examples ====   +
-  * **Analyze Open-Source Code**:   +
-    - Search for generics in libraries like [[https://github.com/axios/axios|Axios]].   +
-    - Example: `get<T = any>(urlstring): Promise<T>`. How does inference work here?   +
-  * **Write Your Own Generic Function**:   +
-    <codeprism typescript> +
-function mapArray<T, U>(arr: T[], fn(item: T) =U): U[] { +
-  return arr.map(fn);+
 } }
-const nums = [1, 2, 3]; +</code>
-const doubled = mapArray(nums, (n) => n * 2); // Inferred as `number[]`   +
-    </codeprism +
  
-==== Step 4: Edge Cases & Explicit Types ====   +Why K is Inferred, Not T?
-  * **When Inference Fails**:   +
-    <codeprism typescript> +
-function merge<T, U>(a: T, b: U): T & U { return { ...a, ...b }; } +
-const merged = merge({ name: "Alice" }, { age: 30 }); // Works   +
-const badMerge = merge({ name: "Bob" }, 42); // Error: No overlap   +
-    </codeprism>    +
-  * **Explicit Type Passing**:   +
-    <codeprism typescript> +
-const explicit = merge<{ name: string }, { age: number }>( +
-  { name: "Alice" },  +
-  { age: 30 } +
-);   +
-    </codeprism>    +
- +
-==== Step 5: Build a Mini-Project ====   +
-  * **Generic `fetchData` Wrapper**:   +
-    <codeprism typescript> +
-async function fetchData<T>(url: string): Promise<T>+
-  const res = await fetch(url); +
-  return res.json(); +
-+
-interface User { id: number; name: string; } +
-const user = await fetchData<User>("https://api.example.com/user/1");   +
-    </codeprism>     +
-  * Test with APIs like [[https://jsonplaceholder.typicode.com|JSONPlaceholder]].   +
- +
-==== Step 6: Advanced Topics ====   +
-  * **Default Type Parameters**:   +
-    <codeprism typescript> +
-function createArray<T = string>(length: number, value: T): T[] { +
-  return Array(length).fill(value); +
-+
-const strArray = createArray(3, "x"); // Inferred as `string[]`   +
-    </codeprism>   +
-  * **Constraints & Inference**:   +
-    <codeprism typescript> +
-function longest<T extends { length: number }>(a: Tb: T): T { +
-  return a.length >= b.length a : b; +
-+
-const longer = longest("hello", "hi"); // Inferred as `string`   +
-    </codeprism>   +
- +
-==== 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://www.typescriptlang.org/play|Playground]] to verify behavior.   +
- +
-==== Resources ====   +
-  * [[https://basarat.gitbook.io/typescript/type-system/generics|TypeScript Deep Dive: Generics]]   +
-  * [[https://www.totaltypescript.com/tips|Matt Pocock’s Advanced Tips]]  +
  
 +TypeScript's inference flows from unknown type parameters based on known argument types:
 +<code typescript>
 +// When you write:
 +config.option('database', 'mysql')
  
 +// TypeScript thinks:
 +// - Receiver type: Chainable<{}>, so T = {} (KNOWN)
 +// - First argument: 'database' (literal string)
 +//   → Must infer K = 'database' (UNKNOWN → INFERRED)
 +// - Second argument: 'mysql' (literal string)  
 +//   → Must infer V = 'mysql' (UNKNOWN → INFERRED)
 +</code>
  
 +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<T, K extends string, V>(
 +    key: Exclude<K, keyof T>, 
 +    value: V
 +  ): Chainable<Omit<T, K> & {[P in K]: V}>
 +}
  
 +// How would TypeScript know what T should be?
 +// There would be no way to infer T from the arguments!
 +</code>
  
 +===== The NoInfer Utility Type =====
  
 +<code lang=typescript el=true >
 +function createStreetLight<C extends string>(colors: C[], defaultColor?: C) {
 +    // ...
 +}
 +createStreetLight(["red", "yellow", "green"], "blue");
 +//                                            ^^^^^ defaultColor?: "red" | "yellow" | "green" | "blue" | undefined
 +//                                                  But I don't want blue, because blue is not the color in colors.
  
  
 +// So
 +function createStreetLight<C extends string>(colors: C[], defaultColor?: NoInfer<C>) {
 +    // ...
 +}
 +createStreetLight(["red", "yellow", "green"], "blue");
 +//                                            ~~~~~~
 +// error!
 +// Argument of type '"blue"' is not assignable to parameter of type '"red" | "yellow" | "green" | undefined'.
  
 +</code>
  
 +===== dokuwiki docker upgrade =====
  
 +<code lang=bash>
 +tar -czvf "$(date +'%Y-%m-%d_%H-%M-%S')_config.tar.gz" ./config 
 +mv *config.tar.gz ./backup
 +docker compose down && docker compose pull && docker compose up -d
 +</code>
  
 +===== 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<[1,2,3]>
 +//   ^ type a = [1, 2, 3]
 +</code>
  • note/tue_jun_17_2025.1750131625.txt.gz
  • Last modified: 2025/06/17 03:40
  • by lingao