# Type API

### $

`Scope` in which chained methods are parsed

### infer

type of output this returns

🥸 inference-only property that will be `undefined` at runtime

```ts
const parseNumber = type("string").pipe(s => Number.parseInt(s))
type ParsedNumber = typeof parseNumber.infer // number
```

### inferIn

type of input this allows

🥸 inference-only property that will be `undefined` at runtime

```ts
const parseNumber = type("string").pipe(s => Number.parseInt(s))
type UnparsedNumber = typeof parseNumber.inferIn // string
```

### json

internal JSON representation

### toJsonSchema

generate a JSON Schema

### meta

metadata like custom descriptions and error messages

✅ type [can be customized](https://arktype.io/docs/configuration#custom) for your project

### description

human-readable English description

✅ works best for primitive values

```ts
const N = type("0 < number <= 100")
console.log(N.description) // positive and at most 100
```

### expression

syntax string similar to native TypeScript

✅ works well for both primitives and structures

```ts
const Loc = type({ coords: ["number", "number"] })
console.log(Loc.expression) // { coords: [number, number] }
```

### assert

validate and return transformed data or throw

✅ sugar to avoid checking for `type.errors` if they are unrecoverable

```ts
const CriticalPayload = type({
    superImportantValue: "string"
})
// throws TraversalError: superImportantValue must be a string (was missing)
const data = CriticalPayload.assert({ irrelevantValue: "whoops" })
console.log(data.superImportantValue) // valid output can be accessed directly
```

### allows

check input without applying morphs

✅ good for stuff like filtering that doesn't benefit from detailed errors

```ts
const Numeric = type("number | bigint")
// [0, 2n]
const numerics = [0, "one", 2n].filter(Numeric.allows)
```

### configure

add metadata to shallow references

⚠️ does not affect error messages within properties of an object

```ts
const NotOdd = type("number % 2").configure({ description: "not odd" })
// all constraints at the root are affected
const odd = NotOdd(3) // must be not odd (was 3)
const nonNumber = NotOdd("two") // must be not odd (was "two")

const NotOddBox = type({
   // we should have referenced notOdd or added meta here
   notOdd: "number % 2",
// but instead chained from the root object
}).configure({ description: "not odd" })
// error message at path notOdd is not affected
const oddProp = NotOddBox({ notOdd: 3 }) // notOdd must be even (was 3)
// error message at root is affected, leading to a misleading description
const nonObject = NotOddBox(null) // must be not odd (was null)
```

### describe

add description to shallow references

🔗 equivalent to `.configure({ description })` (see `configure` )

⚠️ does not affect error messages within properties of an object

```ts
const AToZ = type(/^a.*z$/).describe("a string like 'a...z'")
const good = AToZ("alcatraz") // "alcatraz"
// ArkErrors: must be a string like 'a...z' (was "albatross")
const badPattern = AToZ("albatross")
```

### onUndeclaredKey

apply undeclared key behavior

• `"ignore"` (default) - allow and preserve extra properties

• `"reject"` - disallow extra properties

• `"delete"` - clone and remove extra properties from output

### onDeepUndeclaredKey

deeply apply undeclared key behavior

• `"ignore"` (default) - allow and preserve extra properties

• `"reject"` - disallow extra properties

• `"delete"` - clone and remove extra properties from output

### from

alias for `assert` with typed input

```ts
const T = type({ foo: "string" });
// TypeScript: foo must be a string (was 5)
const data = T.from({ foo: 5 });
```

### brand

add a compile-time brand to output

🥸 inference-only function that does nothing runtime

```ts
const Palindrome = type("string")
    .narrow(s => s === [...s].reverse().join(""))
    .brand("palindrome")
// Brand<string, "palindrome">
const out = Palindrome.assert("racecar")
```

### array

an array of this

```ts
// Type<{ rebmun: number }[]>
const T = type({ rebmun: "number" }).array();
```

### optional

[optional definition](https://arktype.io/docs/objects#properties-optional)

⚠️ unlike most other methods, this creates a definition rather than a Type (read why)

```ts
const Prop = type({ foo: "number" })
// Type<{ bar?: { foo: number } }>
const Obj = type({ bar: Prop.optional() })
```

### default

[defaultable definition](https://arktype.io/docs/objects#properties-defaultable)

✅ object defaults can be returned from a function

⚠️ throws if the default value is not allowed

⚠️ unlike most other methods, this creates a definition rather than a Type (read why)

```ts
// Type<{ count: Default<number, 0> }>
const State = type({ count: type.number.default(0) })
const Prop = type({ nested: "boolean" })
const ForObj = type({
    key: Prop.default(() => ({ nested: false }))
})
```

### filter

apply a predicate function to input

⚠️ the behavior of `narrow` , this method's output counterpart, is usually more desirable

✅ most useful for morphs with input types that are re-used externally

🥸 [Type predicates](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates) can be used as casts

```ts
const stringifyUser = type({ name: "string" }).pipe(user => JSON.stringify(user))
const stringifySafe = stringifyUser.filter(user => user.name !== "Bobby Tables")
// Type<(In: `${string}Z`) => To<Date>>
const WithPredicate = type("string.date.parse").filter((s): s is `${string}Z` =>
    s.endsWith("Z")
)
```

### narrow

apply a predicate function to output

✅ go-to fallback for validation not composable via built-in types and operators

✅ runs after all other validators and morphs, if present

🥸 [Type predicates](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates) can be used as casts

```ts
const Palindrome = type("string").narrow(s => s === [...s].reverse().join(""))

const PalindromicEmail = type("string.date.parse").narrow((date, ctx) =>
		date.getFullYear() === 2025 || ctx.mustBe("the current year")
)
// Type<`${string}.tsx`>
const WithPredicate = type("string").narrow((s): s is `${string}.tsx` => /\.tsx?$/.test(s))
```

### pipe

pipe output through arbitrary transformations or other Types

```ts
const User = type({ name: "string" })

// parse a string and validate that the result as a user
const parseUser = type("string").pipe(s => JSON.parse(s), user)
```

### to

parse a definition as an output validator

🔗 `to({ name: "string" })` is equivalent to `.pipe(type({ name: "string" }))`

```ts
// parse a string and validate that the result as a user
const parseUser = type("string").pipe(s => JSON.parse(s)).to({ name: "string" })
```

### select

query internal node references

filters and returns the Type's internal representation from `@ark/schema`

```ts
// ["blue", "red"]
const values = type("'red' | 'blue'").select("unit").map(u => u.unit)
```

### as

cast the way this is inferred

🥸 inference-only function that does nothing runtime

```ts
// Type<`LEEEEEEEE${string}ROY`>
const Leeroy = type(/^LE{8,}ROY$/).as<`LEEEEEEEE${string}ROY`>()
```

### and

intersect the parsed Type, throwing if the result is unsatisfiable

```ts
// Type<{ foo: number; bar: string }>
const T = type({ foo: "number" }).and({ bar: "string" })
// ParseError: Intersection at foo of number and string results in an unsatisfiable type
const Bad = type({ foo: "number" }).and({ foo: "string" })
```

### or

union with the parsed Type

⚠️ a union that could apply different morphs to the same data is a ParseError ( [docs](https://arktype.io/docs/expressions#union-morphs) )

```ts
// Type<string | { box: string }>
const T = type("string").or({ box: "string" })
```

### intersect

intersect the parsed Type, returning an introspectable `Disjoint` if the result is unsatisfiable

```ts
// Type<{ foo: number; bar: string }>
const T = type({ foo: "number" }).intersect({ bar: "string" })
const Bad = type("number > 10").intersect("number < 5")
// logs "Intersection of > 10 and < 5 results in an unsatisfiable type"
if (Bad instanceof Disjoint) console.log(`${bad.summary}`)
```

### equals

check if the parsed Type's constraints are identical

✅ equal types have identical input and output constraints and transforms

✅ ignores associated `meta` , which does not affect the set of allowed values

```ts
const DivisibleBy6 = type.number.divisibleBy(6).moreThan(0)
// false (left side must also be positive)
DivisibleBy6.equals("number % 6")
// false (right side has an additional <100 constraint)
console.log(DivisibleBy6.equals("0 < (number % 6) < 100"))
const ThirdTry = type("(number % 2) > 0").divisibleBy(3)
// true (types are normalized and reduced)
console.log(DivisibleBy6.equals(ThirdTry))
```

### ifEquals

narrow this based on an `equals` check

✅ ignores associated `meta` , which does not affect the set of allowed values

```ts
const N = type.raw(`${Math.random()}`)
// Type<0.5> | undefined
const Ez = N.ifEquals("0.5")
```

### extends

check if this is a subtype of the parsed Type

✅ a subtype must include all constraints from the base type

✅ unlike `equals` , additional constraints may be present

✅ ignores associated `meta` , which does not affect the set of allowed values

```ts
type.string.extends("unknown") // true
type.string.extends(/^a.*z$/) // false
```

### ifExtends

narrow this based on an `extends` check

✅ ignores associated `meta` , which does not affect the set of allowed values

```ts
const N = type(Math.random() > 0.5 ? "true" : "0") // Type<0 | true>
const Ez = N.ifExtends("boolean") // Type<true> | undefined
```

### overlaps

check if a value could satisfy this and the parsed Type

⚠️ will return true unless a `Disjoint` can be proven

```ts
type.string.overlaps("string | number") // true (e.g. "foo")
type("string | number").overlaps("1") // true (1)
type("number > 0").overlaps("number < 0") // false (no values exist)

const NoAt = type("string").narrow(s => !s.includes("@"))
NoAt.overlaps("string.email") // true (no values exist, but not provable)
```

### extract

extract branches `extend` ing the parsed Type

```ts
// Type<true | 0 | 2>
const T = type("boolean | 0 | 'one' | 2 | bigint").extract("number | 0n | true")
```

### exclude

exclude branches `extend` ing the parsed Type

```ts
// Type<false | 'one' | bigint>
const T = type("boolean | 0 | 'one' | 2 | bigint").exclude("number | 0n | true")
```

The methods below are available on every `Type` instance. For validation and traversal methods (`assert`, `allows`, direct invocation), see the [Traversal API](https://arktype.io/docs/traversal-api). For composition methods (`pipe`, `to`, `narrow`, `filter`, `and`, `or`), see [Expressions](https://arktype.io/docs/expressions). For object-specific methods (`pick`, `omit`, `required`, `partial`, `merge`, `keyof`, `get`, `readonly`, `map`, `props`), see [Objects](https://arktype.io/docs/objects).

### from

`from` is a typed-input variant of `assert`. It accepts an input matching `inferIn` and returns `inferOut`, providing type safety on both sides. Like `assert`, it throws a `TraversalError` on invalid input:

```ts
const StringToNumber = type("string.numeric.parse")

// TypeScript knows the input must be a string
const result = StringToNumber.from("42") // 42

StringToNumber.from(42)
```

### in / out

The `in` and `out` getters extract the input or output Type from a morphed Type, stripping transformations:

```ts
const ParsedUser = type({
	name: "string",
	age: "string.numeric.parse"
})

// Type<{ name: string; age: string }>
const UserInput = ParsedUser.in

// Type<{ name: string; age: number }>
const UserOutput = ParsedUser.out
```

### extends

Check if a Type is a subtype of another:

```ts
const T = type("string")

T.extends("unknown") // true
T.extends("number") // false

// ifExtends returns the Type itself if true, undefined otherwise
const result = T.ifExtends("string | number") // Type<string | number> | undefined
```

### equals

Check if two Types are structurally identical:

```ts
const A = type({ name: "string" })
const B = type({ name: "string" })
const C = type({ name: "number" })

A.equals(B) // true
A.equals(C) // false

// ifEquals returns the Type if equal, undefined otherwise
const result = A.ifEquals(B) // Type<{ name: string }> | undefined
```

### overlaps

Check if any value could satisfy both Types:

```ts
const A = type("string | number")
const B = type("number | boolean")
const C = type("string")

A.overlaps(B) // true (number satisfies both)
C.overlaps(type("number")) // false
```

### extract / exclude

Extract or exclude union branches based on a Type:

```ts
const T = type("string | number | boolean")

// Type<string | boolean>
const Extracted = T.extract("string | boolean")

// Type<number>
const Excluded = T.exclude("string | boolean")
```

### distribute

Map and optionally reduce over union branches:

```ts
const T = type("string | number | bigint")

// ["bigint", "number", "string"]
const expressions = T.distribute(branch => branch.expression)

// with a reducer
const count = T.distribute(
	branch => branch,
	branches => branches.length
) // 3
```

### toJsonSchema

Each `Type` instance exposes a `toJsonSchema()` method that can be used to generate a corresponding JSON Schema.

```ts
const User = type({
	name: "string",
	email: "string.email",
	"age?": "number >= 18"
})

const schema = User.toJsonSchema()

const result = {
	$schema: "https://json-schema.org/draft/2020-12/schema",
	type: "object",
	properties: {
		name: { type: "string" },
		email: {
			type: "string",
			format: "email",
			pattern: "^[\w%+.-]+@[\d.A-Za-z-]+\.[A-Za-z]{2,}$"
		},
		age: { type: "number", minimum: 18 }
	},
	required: ["email", "name"]
}
```

Options can be passed to change the behavior including how incompatibilities are handled. See [the associated config docs](https://arktype.io/docs/configuration#tojsonschema) for more details.
