Skip to content

Your First Type

If you already know TypeScript, congratulations- you just learned most of ArkType’s syntax 🎉

Define

import { type } from "arktype"

const 
const user: Type<{
    name: string;
    platform: "android" | "ios";
    versions?: (string | number)[];
}>
user
= type({
name: "string", platform: "'android' | 'ios'", "versions?": "(number | string)[]" }) // extract the type if needed type
type User = {
    name: string;
    platform: "android" | "ios";
    versions?: (string | number)[];
}
User
= typeof
const user: Type<{
    name: string;
    platform: "android" | "ios";
    versions?: (string | number)[];
}>
user
.infer

If you make a mistake, don’t worry- every definition gets the autocomplete and validation you’re used to from your editor, all within TypeScript’s type system.

Compose

Suppose we want to move platform and version from our original type to a new device property.

const 
const user: Type<{
    name: string;
    device: {
        platform: "android" | "ios";
        versions?: (string | number)[];
    };
}>
user
=
const type: TypeParser
<{
    readonly name: "string";
    readonly device: {
        readonly platform: "'android' | 'ios'";
        readonly "versions?": "(number | string)[]";
    };
}, Type<{
    name: string;
    device: {
        platform: "android" | "ios";
        versions?: (string | number)[];
    };
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type
({
name: "string", // nested definitions don't need to be wrapped device: { platform: "'android' | 'ios'", "versions?": "(number | string)[]" } })

To decouple device from user, just move it to its own type and reference it.

const 
const device: Type<{
    platform: "android" | "ios";
    versions?: (string | number)[];
}>
device
=
const type: TypeParser
<{
    readonly platform: "'android' | 'ios'";
    readonly "versions?": "(number | string)[]";
}, Type<{
    platform: "android" | "ios";
    versions?: (string | number)[];
}, {}>>(def: validateObjectLiteral<{
    readonly platform: "'android' | 'ios'";
    readonly "versions?": "(number | string)[]";
}, {}, bindThis<...>>) => Type<...> (+2 overloads)
type
({
platform: "'android' | 'ios'", "versions?": "(number | string)[]" }) const
const user: Type<{
    name: string;
    device: {
        platform: "android" | "ios";
        versions?: (string | number)[];
    };
}>
user
=
const type: TypeParser
<{
    readonly name: "string";
    readonly device: Type<{
        platform: "android" | "ios";
        versions?: (string | number)[];
    }, {}>;
}, Type<{
    name: string;
    device: {
        platform: "android" | "ios";
        versions?: (string | number)[];
    };
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type
({
name: "string", device:
const device: Type<{
    platform: "android" | "ios";
    versions?: (string | number)[];
}>
device
})

Validate

At runtime, we can pass unknown data to our type and get back either a validated User or an array of clear, customizable errors with a root summary.

const 
const out: {
    name: string;
    device: {
        platform: "android" | "ios";
        versions?: (string | number)[];
    };
} | ArkErrors
out
= user({
name: "Alan Turing", device: { platform: "enigma", versions: [0, "1", 0n] } }) if (
const out: {
    name: string;
    device: {
        platform: "android" | "ios";
        versions?: (string | number)[];
    };
} | ArkErrors
out
instanceof type.errors) {
// hover out.summary to see validation errors console.error(const out: RuntimeErrorsout.RuntimeErrors.summary: string
device.platform must be "android" or "ios" (was "enigma") device.versions[2] must be a number or a string (was bigint)
summary
)
} else { // hover out to see your validated data console.log(`Hello, ${
const out: {
    name: string;
    device: {
        platform: "android" | "ios";
        versions?: (string | number)[];
    };
}
out
.name}`)
}

And that’s it! You now know how to to define a Type use it to check your data at runtime.

Next, we’ll take a look at how ArkType extends TypeScript’s type system to handle runtime constraints like maxLength and pattern.