Generic Type Aliases — Specification¶
Table of Contents¶
- Introduction
- Where Generic Type Aliases Are Specified
- Grammar: Alias Declarations With Type Parameters
- Instantiation and Substitution
- Type Identity (Per Reference)
- Constraint Rules (Per Reference)
- Method Receivers: Why Aliases Are Excluded
- Alias vs Type Definition (Spec Contrast)
- Cyclic Alias Restriction
- Differences Across Go Versions
- References
Introduction¶
Unlike go mod vendor (a tooling feature), generic type aliases are part of the language and are specified in the Go language specification at go.dev/ref/spec. The governing section is "Alias declarations", which in Go 1.24 permits an optional type parameter list on the left of =. Supporting rules come from "Type parameter declarations", "Instantiations", "Type identity", "Satisfying a constraint", and "Method declarations".
Sources of truth, in decreasing formality:
- Go language specification —
go.dev/ref/spec, sections listed above. Authoritative. - Go 1.24 release notes —
go.dev/doc/go1.24#language, which announce the feature. - Proposal #46477 —
go.dev/issue/46477, the design record. - Toolchain /
go/typessource — the de-facto reference where prose is terse.
This file separates "what the spec states" from convention and implementation detail.
Where Generic Type Aliases Are Specified¶
The feature is the composition of two existing spec mechanisms:
- "Alias declarations" — defines
type A = Tand, in Go 1.24,type A[P ...] = T. An alias declaration binds an identifier to a type; with a type parameter list it binds a parameterized name. - "Instantiations" — defines how a generic type name plus type arguments produces a concrete type by substitution. This section already governed generic functions and generic defined types; it applies to generic aliases unchanged.
Nothing about generic aliases requires new identity or constraint semantics; they reuse the rules already in the spec. The only new grammar is the optional TypeParameters on an AliasDecl.
Grammar: Alias Declarations With Type Parameters¶
The spec grammar for an alias declaration, as of Go 1.24:
Where TypeParameters is the standard bracketed list shared with function and type-definition declarations:
TypeParameters = "[" TypeParamList [ "," ] "]" .
TypeParamList = TypeParamDecl { "," TypeParamDecl } .
TypeParamDecl = IdentifierList TypeConstraint .
Examples that parse under this grammar:
type Set[T comparable] = map[T]struct{}
type Pair[A, B any] = struct{ First A; Second B }
type Handler[T any] = func(context.Context, T) error
type Map[K comparable, V any] = map[K]V
Constraints:
- The type parameter list is optional. Without it, the declaration is an ordinary (non-generic) alias as in Go 1.9+.
- When present, the alias is generic and must be instantiated before use as a type.
- The
Typeon the right of=(the RHS) may reference the declared type parameters.
Instantiation and Substitution¶
Per the spec's "Instantiations" section, a generic type is instantiated by substituting type arguments for its type parameters. For a generic alias type Alias[P ...] = RHS, the instantiation Alias[Args] denotes:
Worked examples (the ≡ denotes "denotes / is identical to"):
Set[string] ≡ map[string]struct{}
Pair[int, bool] ≡ struct{ First int; Second bool }
Map[string, int] ≡ map[string]int
Handler[Request] ≡ func(context.Context, Request) error
The spec is explicit that instantiation requires each type argument to satisfy the corresponding type parameter's constraint (see Constraint Rules). A bare generic alias name used where a type is required, without arguments, is an error — instantiation is mandatory.
Partial specialization through a further alias is permitted, producing a new generic alias with fewer parameters:
type StringMap[V any] = Map[string, V] // one parameter remains
StringMap[int] ≡ Map[string, int] ≡ map[string]int
Type Identity (Per Reference)¶
The spec's "Type identity" section governs when two types are the same. The operative principle for aliases is that an alias denotes its RHS; the alias name has no independent identity. Therefore:
Alias[Args]is identical to the substituted RHS.- Two alias instantiations are identical iff their substituted RHS types are identical.
- An alias instantiation is identical to a hand-written type equal to the substituted RHS.
Per the reference, this means:
type Set[T comparable] = map[T]struct{}
var a Set[int]
var b map[int]struct{}
a = b // valid: identical types, no conversion
When the RHS is (or contains) a defined generic type, identity is the named-type identity of that defined type with its arguments — not the structural shape:
type C[K comparable, V any] = pkg.Cache[K, V]
// C[string,int] is identical to pkg.Cache[string,int]
// It is NOT identical to a struct of the same layout, because
// pkg.Cache is a defined type whose identity is by name.
This follows directly from the spec: aliases resolve through, defined types stop at their name.
Constraint Rules (Per Reference)¶
Two spec rules apply.
1. Constraint satisfaction at instantiation. Per "Satisfying a constraint", each type argument to Alias[Args] must satisfy the corresponding parameter's declared constraint:
type Set[T comparable] = map[T]struct{}
Set[string] // string satisfies comparable — valid
Set[[]int] // []int does not satisfy comparable — error
2. Well-formedness of the RHS for every instantiation. The spec requires types to be well-formed. Because the RHS must be valid for every satisfying argument, the alias's declared constraints must be at least as strong as the RHS demands. The compiler enforces this at declaration time:
type Set[T comparable] = map[T]struct{} // OK: comparable suffices for a map key
type Bad[T any] = map[T]struct{} // error: any permits non-comparable map keys
You may declare a constraint stronger than required (narrowing callers); you may not declare a weaker one. The reference treats this as an instance of the general rule that a generic type's parameters must guarantee a valid type for all permitted arguments — the same obligation a generic defined type carries via its underlying type.
Method Receivers: Why Aliases Are Excluded¶
The spec's "Method declarations" section requires the receiver base type to be a defined type declared in the same package (or a pointer to one). An alias is not a defined type; it is a name denoting another type. Consequently, a method cannot be declared with an alias as its receiver:
type Set[T comparable] = map[T]struct{}
func (s Set[T]) Add(v T) {} // illegal: receiver base is not a defined type
The spec does not carve out a special case for generic aliases — the general receiver rule already excludes them, because substituting the alias yields a composite type literal (map[...]...), which is not a valid receiver base. To declare methods, the program must use a type definition (no =):
type Set[T comparable] map[T]struct{} // defined type
func (s Set[T]) Add(v T) { s[v] = struct{}{} } // valid
This is the spec-level reason transparency and methods are mutually exclusive.
Alias vs Type Definition (Spec Contrast)¶
The spec distinguishes two declarations sharing the type keyword:
| Alias declaration | Type definition | |
|---|---|---|
| Syntax | type A[P ...] = T | type A[P ...] T |
| Creates a new type? | No — denotes T | Yes — a new defined type |
Identity with T | Identical (after subst.) | Distinct; T is the underlying type |
| Methods | Not permitted | Permitted |
Conversion to/from T | Not needed (identical) | Required |
| Spec section | "Alias declarations" | "Type definitions" |
The single token = selects between them. Both accept the same TypeParameters grammar in Go 1.24.
Cyclic Alias Restriction¶
The spec forbids an alias whose definition refers to itself such that resolution does not terminate. Because an alias denotes its RHS by substitution, a cycle of aliases never bottoms out:
By contrast, a defined type may be recursive, because its name provides a finite reference point that breaks the cycle:
The reference treats this as a consequence of the difference between denoting (aliases) and naming (defined types).
Differences Across Go Versions¶
The behavior of type aliases has evolved:
- Go 1.9 — Type aliases introduced:
type A = B. No type parameters (generics did not exist). - Go 1.18 — Generics introduced (type parameters on functions and defined types). Parameterized aliases were deliberately deferred (tracked by proposal #46477).
- Go 1.23 — Experimental, partial support for type parameters on aliases, gated behind
GOEXPERIMENT=aliastypeparams. Off by default; not covered by the compatibility promise. - Go 1.24 — Full support, enabled by default. Generic type aliases are standard Go. Announced in the Go 1.24 release notes under language changes. This is the version to target.
The grammar addition (optional TypeParameters on AliasDecl) is the only language change; identity, constraint, instantiation, and receiver rules were reused unchanged.
A library that uses generic aliases in its public API thereby requires consumers to build with Go 1.24+. Set go 1.24 (or later) in go.mod so the toolchain enforces and diagnoses the minimum cleanly.
References¶
- Go language specification — authoritative.
- Spec — Alias declarations — the parameterized form.
- Spec — Type definitions — contrast with defined types.
- Spec — Instantiations — substitution rules.
- Spec — Type identity — why
Set[int]≡map[int]struct{}. - Spec — Satisfying a constraint — instantiation constraint checks.
- Spec — Method declarations — the receiver rule that excludes aliases.
- Go 1.24 Release Notes — Language — feature announcement.
- Proposal #46477 — spec: allow type parameters on type aliases.
In this topic