====== TS ====== typehero declare const config: Chainable const result = config .option('foo', 123) .option('name', 'type-challenges') .option('bar', { value: 'Hello World' }) .get() // expect the type of result to be: interface Result { foo: number name: string bar: { value: string } } ===== Type Argument Inference in TypeScript ===== ==== Goal: Understand how TypeScript infers type arguments ==== type Chainable = { option(key: Exclude, value: V): Chainable & {[P in K]: V}> get(): T } Why K is Inferred, Not T? TypeScript's inference flows from unknown type parameters based on known argument types: // 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) What If T Were Also a Type Parameter? If we hypothetically made T also inferrable, it would create ambiguity: // Hypothetical (problematic) design: type BadChainable = { option( key: Exclude, value: V ): Chainable & {[P in K]: V}> } // How would TypeScript know what T should be? // There would be no way to infer T from the arguments! ===== The NoInfer Utility Type ===== function createStreetLight(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(colors: C[], defaultColor?: NoInfer) { // ... } createStreetLight(["red", "yellow", "green"], "blue"); // ~~~~~~ // error! // Argument of type '"blue"' is not assignable to parameter of type '"red" | "yellow" | "green" | undefined'. ===== dokuwiki docker upgrade ===== 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 ===== Tuple Map ===== we can use mapped types for creating tuples. It's because tuple properties are indexes. type A = { [P in keyof T] : T[P] } type a = A<[1,2,3]> // ^ type a = [1, 2, 3]