Skip to content

Objects

properties

Objects definitions can include any combination of required, optional, defaultable named properties and index signatures.

required
const const symbolicKey: typeof symbolicKeysymbolicKey = Symbol()

const 
const myObject: Type<{
    requiredKey: string;
    [symbolicKey]: {
        nested: unknown;
    };
}>
myObject
=
const type: TypeParser
<{
    readonly requiredKey: "string";
    readonly [symbolicKey]: {
        readonly nested: "unknown";
    };
}, Type<{
    requiredKey: string;
    [symbolicKey]: {
        nested: unknown;
    };
}, {}>>(def: validateObjectLiteral<{
    readonly requiredKey: "string";
    readonly [symbolicKey]: {
        readonly nested: "unknown";
    };
}, {}, bindThis<...>>) => Type<...> (+2 overloads)
type
({
requiredKey: "string", // Nested definitions don't require additional `type` calls! [const symbolicKey: typeof symbolicKeysymbolicKey]: { nested: "unknown" } })
optional
const const symbolicKey: typeof symbolicKeysymbolicKey = Symbol()

const 
const myObject: Type<{
    [symbolicKey]: string.optional;
    optionalKey?: number[];
}>
myObject
=
const type: TypeParser
<{
    readonly "optionalKey?": "number[]";
    readonly [symbolicKey]: "string?";
}, Type<{
    [symbolicKey]: string.optional;
    optionalKey?: number[];
}, {}>>(def: validateObjectLiteral<{
    readonly "optionalKey?": "number[]";
    readonly [symbolicKey]: "string?";
}, {}, bindThis<...>>) => Type<...> (+2 overloads)
type
({
"optionalKey?": "number[]", [const symbolicKey: typeof symbolicKeysymbolicKey]: "string?" })
defaultable
const 
const myObject: Type<{
    defaultableKey: of<boolean, Default<false>>;
}>
myObject
=
const type: TypeParser
<{
    readonly defaultableKey: "boolean = false";
}, Type<{
    defaultableKey: of<boolean, Default<false>>;
}, {}>>(def: validateObjectLiteral<{
    readonly defaultableKey: "boolean = false";
}, {}, bindThis<...>>) => Type<...> (+2 overloads)
type
({
defaultableKey: "boolean = false" })
index
const 
const myObject: Type<{
    [x: string]: number | integer;
    [x: symbol]: number;
}>
myObject
=
const type: TypeParser
<{
    readonly "[string]": "number.integer";
    readonly "[string | symbol]": "number";
}, Type<{
    [x: string]: number | integer;
    [x: symbol]: number;
}, {}>>(def: validateObjectLiteral<{
    readonly "[string]": "number.integer";
    readonly "[string | symbol]": "number";
}, {}, bindThis<...>>) => Type<...> (+2 overloads)
type
({
// index signatures do not require a label "[string]": "number.integer", // arbitrary string or symbolic expressions are allowed "[string | symbol]": "number" })
undeclared

🚧 Coming soon ™️🚧

merge

🚧 Coming soon ™️🚧

keyof

🚧 Coming soon ™️🚧

get

🚧 Coming soon ™️🚧

arrays

const 
const arrays: Type<{
    key: string[];
}>
arrays
=
const type: TypeParser
<{
    readonly key: "string[]";
}, Type<{
    key: string[];
}, {}>>(def: validateObjectLiteral<{
    readonly key: "string[]";
}, {}, bindThis<{
    readonly key: "string[]";
}>>) => Type<...> (+2 overloads)
type
({
key: "string[]" })
lengths

Constrain an array with an inclusive or exclusive min or max length.

const 
const bounded: Type<{
    nonEmptyStringArray: of<string[], MoreThanLength<0>>;
    atLeast3Integers: of<integer[], AtLeastLength<3>>;
    lessThan10Emails: of<string.email[], LessThanLength<10>>;
    atMost5Booleans: of<boolean[], AtMostLength<5>>;
}>
bounded
=
const type: TypeParser
<{
    readonly nonEmptyStringArray: "string[] > 0";
    readonly atLeast3Integers: "number.integer[] >= 3";
    readonly lessThan10Emails: "string.email[] < 10";
    readonly atMost5Booleans: "boolean[] <= 5";
}, Type<...>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type
({
nonEmptyStringArray: "string[] > 0", atLeast3Integers: "number.integer[] >= 3", lessThan10Emails: "string.email[] < 10", atMost5Booleans: "boolean[] <= 5" })

Range expressions allow you to specify both a min and max length and use the same syntax for exclusivity.

const 
const range: Type<{
    nonEmptyStringArrayAtMostLength10: of<string[], AtMostLength<10> & MoreThanLength<0>>;
    twoToFiveIntegers: of<integer[], LessThanLength<6> & AtLeastLength<2>>;
}>
range
=
const type: TypeParser
<{
    readonly nonEmptyStringArrayAtMostLength10: "0 < string[] <= 10";
    readonly twoToFiveIntegers: "2 <= number.integer[] < 6";
}, Type<{
    nonEmptyStringArrayAtMostLength10: of<string[], AtMostLength<...> & MoreThanLength<...>>;
    twoToFiveIntegers: of<...>;
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type
({
nonEmptyStringArrayAtMostLength10: "0 < string[] <= 10", twoToFiveIntegers: "2 <= number.integer[] < 6" })

tuples

Like objects, tuples are structures whose values are nested definitions. Like TypeScript, ArkType supports prefix, optional, variadic, and postfix elements, with the same restrictions about combining them.

prefix
const 
const myTuple: Type<[string, {
    coordinates: [number, number];
}]>
myTuple
=
const type: TypeParser
<readonly ["string", {
    readonly coordinates: readonly ["number", "number"];
}], Type<[string, {
    coordinates: [number, number];
}], {}>>(def: readonly ["string", validateObjectLiteral<{
    readonly coordinates: readonly ["number", "number"];
}, {}, bindThis<...>>]) => Type<...> (+2 overloads)
type
([
"string", // Object definitions can be nested in tuples- and vice versa! { coordinates: ["number", "number"] } ])
optional

Tuples can include any number of optional elements following its prefix elements.

Like in TypeScript, optional elements are mutually exclusive with postfix elements.

const const myTuple: Type<[string, boolean?, number?]>myTuple = 
const type: TypeParser
<readonly ["string", "boolean?", "number?"], Type<[string, boolean?, number?], {}>>(def: readonly ["string", "boolean?", "number?"]) => Type<[string, boolean?, number?], {}> (+2 overloads)
type
(["string", "boolean?", "number?"])
variadic

Like in TypeScript, variadic elements allow zero or more consecutive values of a given type and may occur at most once in a tuple.

They are specified with a "..." operator preceding an array element.

// allows a string followed by zero or more numbers
const const myTuple: Type<[string, ...number[]]>myTuple = 
const type: TypeParser
<readonly ["string", "...", "number[]"], Type<[string, ...number[]], {}>>(def: readonly ["string", "...", "number[]"]) => Type<[string, ...number[]], {}> (+2 overloads)
type
(["string", "...", "number[]"])
postfix

Postfix elements are required elements following a variadic element.

They are mutually exclusive with optional elements.

// allows zero or more numbers followed by a boolean, then a string
const const myTuple: Type<[...number[], boolean, string]>myTuple = 
const type: TypeParser
<readonly ["...", "number[]", "boolean", "string"], Type<[...number[], boolean, string], {}>>(def: readonly ["...", "number[]", "boolean", "string"]) => Type<[...number[], boolean, string], {}> (+2 overloads)
type
(["...", "number[]", "boolean", "string"])

dates

literals

Date literals represent a Date instance with an exact value.

They’re primarily useful in ranges.

const 
const literals: Type<{
    singleQuoted: Date.nominal<"01-01-1970">;
    doubleQuoted: Date.nominal<"01-01-1970">;
}>
literals
=
const type: TypeParser
<{
    readonly singleQuoted: "d'01-01-1970'";
    readonly doubleQuoted: "d\"01-01-1970\"";
}, Type<{
    singleQuoted: Date.nominal<"01-01-1970">;
    doubleQuoted: Date.nominal<"01-01-1970">;
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type
({
singleQuoted: "d'01-01-1970'", doubleQuoted: 'd"01-01-1970"' })
ranges

Constrain a Date with an inclusive or exclusive min or max.

Bounds can be expressed as either a number representing its corresponding Unix epoch value or a Date literal.

const 
const bounded: Type<{
    dateInThePast: Date.before<number>;
    dateAfter2000: Date.after<"2000-01-01">;
    dateAtOrAfter1970: Date.atOrAfter<0>;
}>
bounded
=
const type: TypeParser
<{
    readonly dateInThePast: `Date < ${number}`;
    readonly dateAfter2000: "Date > d'2000-01-01'";
    readonly dateAtOrAfter1970: "Date >= 0";
}, Type<{
    dateInThePast: Date.before<number>;
    dateAfter2000: Date.after<...>;
    dateAtOrAfter1970: Date.atOrAfter<...>;
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type
({
dateInThePast: `Date < ${Date.now()}`, dateAfter2000: "Date > d'2000-01-01'", dateAtOrAfter1970: "Date >= 0" })

Range expressions allow you to specify both a min and max and use the same syntax for exclusivity.

const const tenYearsAgo: numbertenYearsAgo = new Date()
	.setFullYear(new Date().getFullYear() - 10)
	.valueOf()

const 
const bounded: Type<{
    dateInTheLast10Years: Date.is<Before<number> & AtOrAfter<number>>;
}>
bounded
=
const type: TypeParser
<{
    readonly dateInTheLast10Years: `${number} <= Date < ${number}`;
}, Type<{
    dateInTheLast10Years: Date.is<Before<number> & AtOrAfter<number>>;
}, {}>>(def: validateObjectLiteral<{
    readonly dateInTheLast10Years: `${number} <= Date < ${number}`;
}, {}, bindThis<...>>) => Type<...> (+2 overloads)
type
({
dateInTheLast10Years: `${const tenYearsAgo: numbertenYearsAgo} <= Date < ${Date.now()}` })

instanceof

Most builtin instance types like Array and Date are available directly as keywords, but instanceof can be useful for constraining a type to one of your own classes.

class MyClass {}

const const instances: Type<MyClass>instances = type.instanceOf(MyClass)
keywords

🚧 Coming soon ™️🚧