Skip to content
webtype.orgTwelve concepts · 2/12

Concept 2 of 12

Generic parameters

A generic parameter turns an alias into a function that takes types and returns a type. Once you read it that way — arguments in, type out — the rest of the type system stops looking like syntax and starts looking like programming.

Parameters, defaults and all

type Box<T> = { value: T }
type Boxed = Box<string>        // { value: string }

// Defaults work exactly like function parameter defaults.
type List<T, Sep extends string = ','> = { items: T[]; sep: Sep }
type Plain = List<number>       // sep is ','

Type parameters are positional, can have defaults, and the defaults may reference earlier parameters. Recursive type-level code leans on this constantly: an accumulator is nearly always a defaulted parameter the caller never passes.

`extends` here means "must be at least"

type Length<S extends string> = S['length']

Length<'abc'>   // ok
Length<42>      // Error: 42 does not satisfy the constraint 'string'

In a parameter list, `extends` is a constraint: it restricts what may be passed. It is not inheritance, and it does not mean the parameter *is* that type — only that whatever arrives is assignable to it.

The same keyword means something completely different inside a conditional type, where it asks a question rather than imposing a rule. Telling the two apart by position is one of the genuine hurdles in learning this.

The common wrong answer

// Intent: accept any object and read a key from it.
type Get<T, K> = T[K]
//                 ^ Error: type K cannot be used to index type T

// Fixed: constrain K to the keys T actually has.
type Get2<T, K extends keyof T> = T[K]

Without a constraint the compiler has no reason to believe `K` is a valid key, so it refuses. Constraints are not decoration — they are what lets the body of a generic type do anything with its parameters.

Takeaway

Read `type F<A, B> = ...` as a function from types to types. `extends` in the parameter list is the argument check at the door.