====== 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]