Generics

Keywords

This table includes all generic keywords available in default type API.

AliasDescription
Excludeexclude branches of a union like Exclude("boolean", "true")
Extractextract branches of a union like Extract("0 | false | 1", "number")
Mergemerge an object's properties onto another like Merge(User, { isAdmin: "true" })
Omitomit a set of properties from an object like Omit(User, "age")
Partialmake all named properties of an object optional like Partial(User)
Pickpick a set of properties from an object like Pick(User, "name | age")
Recordinstantiate an object from an index signature and corresponding value type like Record("string", "number")
Requiredmake all named properties of an object required like Required(User)

Syntax

Generics can be declared and instantiated in one of three ways.

Definition

import { type } from "arktype"

const  = type("<t>", { box: "t" })

// hover me!
const  = ({ cat: { isAlive: "boolean" } })

Constrained Parameters

All syntax in parameters definitions and all references to generic args are fully-type safe and autocompleted like any built-in keyword. Constraints can be used just like TS to limit what can be passed to a generic and allow that arg to be used with operators like >.

import { type } from "arktype"

const  = type("<arr extends unknown[]>", "arr > 0")

const  = ("number[]")

Scoped

There is a special syntax for specifying generics in a scope:

import { scope } from "arktype"

const  = scope({
	"box<t, u>": {
		box: "t | u"
	},
	bitBox: "box<0, 1>"
}).export()

const  = .bitBox({ box: 0 })

Invocation

import { type } from "arktype"

const  = type("Extract<0 | 1, 1>")
Chained
import { type } from "arktype"

const  = type({
	name: "string",
	"age?": "number",
	isAdmin: "boolean"
})

// hover me!
const  = .pick("name", "age")

Invoked

import { type } from "arktype"

const  = type.keywords.Exclude("boolean", "false")

HKT

Our new generics have been built using a new method for integrating arbitrary external types as native ArkType generics! This opens up tons of possibilities for external integrations that would otherwise not be possible. As a preview, here's what the implementation of Partial looks like internally:

import { generic, Hkt } from "arktype"

const  = generic(["T", "object"])(
	args => args.T.partial(),
	class PartialHkt extends Hkt<[object]> {
		declare body: <this[0]>
	}
)

Recursive and cyclic generics are also currently unavailable and will be added soon.

For more usage examples, check out the unit tests for generics here.

External

The most basic pattern for wrapping a Type looks something like this:

const  = <t extends string>(of: type.Any<t>) =>
	({
		box: of
	})

// @ts-expect-error
(("number"))

// Type<{ box: string }>
const  = (("string"))

For a deeper integration, you may wish to parse a definition directly:

const  = <const def>(
	of: type.<def>
): type.<{ of: def }> =>
	type.raw({
		box: of
	}) as never

// Type<{ box: string }>
const  = ("string")

The sky's the limit when it comes to this sort of integration, but be warned- TypeScript generics are notoriously finicky and you may find APIs like these difficult to write if you're not used to it.

On this page