Objects
properties
Objects definitions can include any combination of required, optional, defaultable named properties and index signatures.
required
const const symbolicKey: typeof symbolicKey
symbolicKey = 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 symbolicKey
symbolicKey]: {
nested: "unknown"
}
})
const const symbolicKey: typeof symbolicKey
symbolicKey = Symbol()
const const myObject: Type<{
requiredKey: string;
[symbolicKey]: {
nested: unknown;
};
}>
myObject = const type: TypeParser
<{
readonly requiredKey: Type<string, {}>;
readonly [symbolicKey]: {
readonly nested: Type<unknown, {}>;
};
}, Type<{
requiredKey: string;
[symbolicKey]: {
nested: unknown;
};
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
requiredKey: type.string,
// Nested definitions don't require additional `type` calls!
[const symbolicKey: typeof symbolicKey
symbolicKey]: {
nested: type.unknown
}
})
optional
const const symbolicKey: typeof symbolicKey
symbolicKey = Symbol()
const const myObject: Type<{
optionalKey?: number[];
[symbolicKey]?: string;
}>
myObject = const type: TypeParser
<{
readonly "optionalKey?": "number[]";
readonly [symbolicKey]: "string?";
}, Type<{
optionalKey?: number[];
[symbolicKey]?: string;
}, {}>>(def: validateObjectLiteral<{
readonly "optionalKey?": "number[]";
readonly [symbolicKey]: "string?";
}, {}, bindThis<...>>) => Type<...> (+2 overloads)
type({
"optionalKey?": "number[]",
[const symbolicKey: typeof symbolicKey
symbolicKey]: "string?"
})
const const symbolicKey: typeof symbolicKey
symbolicKey = Symbol()
const const myObject: Type<{
optionalKey?: number[];
[symbolicKey]?: string;
}>
myObject = const type: TypeParser
<{
readonly optionalKey: [Type<number[], {}>, "?"];
readonly [symbolicKey]: [Type<string, {}>, "?"];
}, Type<{
optionalKey?: number[];
[symbolicKey]?: string;
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
optionalKey: type.number.array().optional(),
[const symbolicKey: typeof symbolicKey
symbolicKey]: type.string.optional()
})
const const symbolicKey: typeof symbolicKey
symbolicKey = Symbol()
const const myObject: Type<{
optionalKey?: {
type: "script";
};
[symbolicKey]?: {
ark: "type";
};
}>
myObject = const type: TypeParser
<{
readonly optionalKey: readonly [{
readonly type: "'script'";
}, "?"];
readonly [symbolicKey]: readonly [{
readonly ark: "'type'";
}, "?"];
}, Type<{
optionalKey?: {
type: "script";
};
[symbolicKey]?: {
...;
};
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
optionalKey: [{ type: "'script'" }, "?"],
[const symbolicKey: typeof symbolicKey
symbolicKey]: [{ ark: "'type'" }, "?"]
})
const const symbolicKey: typeof symbolicKey
symbolicKey = Symbol()
const const myObject: Type<{
optionalKey: {
type: "script";
};
[symbolicKey]: {
ark: "type";
};
}>
myObject = const type: TypeParser
<{
readonly optionalKey: Type<{
type: "script";
}, {}>;
readonly [symbolicKey]: Type<{
ark: "type";
}, {}>;
}, Type<{
optionalKey: {
type: "script";
};
[symbolicKey]: {
ark: "type";
};
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
optionalKey: const type: TypeParser
<{
readonly type: "'script'";
}, "?", readonly [], Type<{
type: "script";
}, {}>>(_0: validateObjectLiteral<{
readonly type: "'script'";
}, {}, bindThis<{
readonly type: "'script'";
}>>, _1: "?") => Type<...> (+2 overloads)
type({ type: "'script'" }, "?"),
[const symbolicKey: typeof symbolicKey
symbolicKey]: const type: TypeParser
<{
readonly ark: "'type'";
}, "?", readonly [], Type<{
ark: "type";
}, {}>>(_0: validateObjectLiteral<{
readonly ark: "'type'";
}, {}, bindThis<{
readonly ark: "'type'";
}>>, _1: "?") => Type<...> (+2 overloads)
type({ ark: "'type'" }, "?")
})
defaultable
const const myObject: Type<{
defaultableKey: Default<boolean, false>;
}>
myObject = const type: TypeParser
<{
readonly defaultableKey: "boolean = false";
}, Type<{
defaultableKey: Default<boolean, false>;
}, {}>>(def: validateObjectLiteral<{
readonly defaultableKey: "boolean = false";
}, {}, bindThis<...>>) => Type<...> (+2 overloads)
type({
defaultableKey: "boolean = false"
})
const const myObject: Type<{
defaultableKey: Default<boolean, false>;
}>
myObject = const type: TypeParser
<{
readonly defaultableKey: [Type<boolean, {}>, "=", false];
}, Type<{
defaultableKey: Default<boolean, false>;
}, {}>>(def: validateObjectLiteral<{
readonly defaultableKey: [Type<boolean, {}>, "=", false];
}, {}, bindThis<...>>) => Type<...> (+2 overloads)
type({
defaultableKey: type.boolean.default(false)
})
const const myObject: Type<{
defaultableKey: Default<boolean, false>;
}>
myObject = const type: TypeParser
<{
readonly defaultableKey: readonly ["boolean", "=", false];
}, Type<{
defaultableKey: Default<boolean, false>;
}, {}>>(def: validateObjectLiteral<{
readonly defaultableKey: readonly ["boolean", "=", false];
}, {}, bindThis<...>>) => Type<...> (+2 overloads)
type({
defaultableKey: ["boolean", "=", false]
})
index
const const myObject: Type<{
[x: string]: number;
[x: symbol]: number;
}>
myObject = const type: TypeParser
<{
readonly "[string]": "number.integer";
readonly "[string | symbol]": "number";
}, Type<{
[x: string]: number;
[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[]"
})
const const arrays: Type<{
key: string[];
}>
arrays = const type: TypeParser
<{
readonly key: Type<string[], {}>;
}, Type<{
key: string[];
}, {}>>(def: validateObjectLiteral<{
readonly key: Type<string[], {}>;
}, {}, bindThis<{
readonly key: Type<string[], {}>;
}>>) => Type<...> (+2 overloads)
type({
key: type.string.array()
})
const const arrays: Type<{
key: {
name: string;
}[];
}>
arrays = const type: TypeParser
<{
readonly key: readonly [{
readonly name: "string";
}, "[]"];
}, Type<{
key: {
name: string;
}[];
}, {}>>(def: validateObjectLiteral<{
readonly key: readonly [{
readonly name: "string";
}, "[]"];
}, {}, bindThis<{
readonly key: readonly [{
readonly name: "string";
}, "[]"];
}>>) => Type<...> (+2 overloads)
type({
key: [{ name: "string" }, "[]"]
})
const const arrays: Type<{
key: {
name: string;
}[];
}>
arrays = const type: TypeParser
<{
readonly key: Type<{
name: string;
}[], {}>;
}, Type<{
key: {
name: string;
}[];
}, {}>>(def: validateObjectLiteral<{
readonly key: Type<{
name: string;
}[], {}>;
}, {}, bindThis<{
readonly key: Type<{
name: string;
}[], {}>;
}>>) => Type<...> (+2 overloads)
type({
key: const type: TypeParser
<{
readonly name: "string";
}, "[]", readonly [], Type<{
name: string;
}[], {}>>(_0: validateObjectLiteral<{
readonly name: "string";
}, {}, bindThis<{
readonly name: "string";
}>>, _1: "[]") => Type<...> (+2 overloads)
type({ name: "string" }, "[]")
})
lengths
Constrain an array with an inclusive or exclusive min or max length.
const const bounded: Type<{
nonEmptyStringArray: string[];
atLeast3Integers: number[];
lessThan10Emails: string[];
atMost5Booleans: boolean[];
}>
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"
})
const const bounded: Type<{
nonEmptyStringArray: string[];
atLeast3Integers: number[];
lessThan10Emails: string[];
atMost5Booleans: boolean[];
}>
bounded = const type: TypeParser
<{
readonly nonEmptyStringArray: Type<string[], {}>;
readonly atLeast3Integers: Type<number[], Ark>;
readonly lessThan10Emails: Type<string[], Ark>;
readonly atMost5Booleans: Type<...>;
}, Type<...>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
nonEmptyStringArray: type.string.array().moreThanLength(0),
atLeast3Integers: type.keywords.number.integer.array().atLeastLength(3),
lessThan10Emails: type.keywords.string.email.array().lessThanLength(10),
atMost5Booleans: type.boolean.array().atMostLength(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: string[];
twoToFiveIntegers: number[];
}>
range = const type: TypeParser
<{
readonly nonEmptyStringArrayAtMostLength10: "0 < string[] <= 10";
readonly twoToFiveIntegers: "2 <= number.integer[] < 6";
}, Type<{
nonEmptyStringArrayAtMostLength10: string[];
twoToFiveIntegers: number[];
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
nonEmptyStringArrayAtMostLength10: "0 < string[] <= 10",
twoToFiveIntegers: "2 <= number.integer[] < 6"
})
const const range: Type<{
nonEmptyStringArrayAtMostLength10: string[];
twoToFiveIntegers: number[];
}>
range = const type: TypeParser
<{
readonly nonEmptyStringArrayAtMostLength10: Type<string[], {}>;
readonly twoToFiveIntegers: Type<number[], Ark>;
}, Type<{
nonEmptyStringArrayAtMostLength10: string[];
twoToFiveIntegers: number[];
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
nonEmptyStringArrayAtMostLength10: type.string
.array()
.moreThanLength(0)
.atMostLength(10),
twoToFiveIntegers: type.keywords.number.integer
.array()
.atLeastLength(2)
.lessThanLength(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"]
}
])
const const myTuple: Type<[string, {
coordinates: [number, number];
}]>
myTuple = const type: TypeParser
<readonly [Type<string, {}>, {
readonly coordinates: readonly [Type<number, {}>, Type<number, {}>];
}], Type<[string, {
coordinates: [number, number];
}], {}>>(def: readonly [Type<string, {}>, validateObjectLiteral<...>]) => Type<...> (+2 overloads)
type([
type.string,
// Object definitions can be nested in tuples- and vice versa!
{
coordinates: [type.number, type.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?"])
const const myTuple: Type<[string, boolean?, number?]>
myTuple = const type: TypeParser
<readonly [Type<string, {}>, [Type<boolean, {}>, "?"], [Type<number, {}>, "?"]], Type<[string, boolean?, number?], {}>>(def: readonly [Type<string, {}>, readonly [Type<boolean, {}>, "?"], readonly [...]]) => Type<...> (+2 overloads)
type([
type.string,
type.boolean.optional(),
type.number.optional()
])
const const myTuple: Type<[string, {
name: string;
}?]>
myTuple = const type: TypeParser
<readonly ["string", readonly [{
readonly name: "string";
}, "?"]], Type<[string, {
name: string;
}?], {}>>(def: readonly ["string", readonly [validateObjectLiteral<{
readonly name: "string";
}, {}, bindThis<readonly ["string", readonly [{
readonly name: "string";
}, "?"]]>>, "?"]]) => Type<...> (+2 overloads)
type([
"string",
[
{
name: "string"
},
"?"
]
])
const const myTuple: Type<[string, {
name: string;
}]>
myTuple = const type: TypeParser
<readonly ["string", Type<{
name: string;
}, {}>], Type<[string, {
name: string;
}], {}>>(def: readonly ["string", Type<{
name: string;
}, {}>]) => Type<[string, {
name: string;
}], {}> (+2 overloads)
type([
"string",
const type: TypeParser
<{
readonly name: "string";
}, "?", readonly [], Type<{
name: string;
}, {}>>(_0: validateObjectLiteral<{
readonly name: "string";
}, {}, bindThis<{
readonly name: "string";
}>>, _1: "?") => Type<...> (+2 overloads)
type(
{
name: "string"
},
"?"
)
])
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[]"])
// allows a string followed by zero or more numbers
const const myTuple: Type<[string, ...number[]]>
myTuple = const type: TypeParser
<readonly [Type<string, {}>, "...", Type<number[], {}>], Type<[string, ...number[]], {}>>(def: readonly [Type<...>, "...", Type<...>]) => Type<...> (+2 overloads)
type([type.string, "...", type.number.array()])
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"])
// allows zero or more numbers followed by a boolean, then a string
const const myTuple: Type<[...number[], boolean, string]>
myTuple = const type: TypeParser
<readonly ["...", Type<number[], {}>, Type<boolean, {}>, Type<string, {}>], Type<[...number[], boolean, string], {}>>(def: readonly [...]) => Type<...> (+2 overloads)
type(["...", type.number.array(), type.boolean, type.string])
dates
literals
Date literals represent a Date instance with an exact value.
It is recommended that the date literal string content be in JavaScript date-time format.
The value of a Date literal is determined by constructing a new Date(dateLiteralContents)
, though, so any string format accepted by Date()
is acceptable.
A Date literal that results in an invalid Date will throw a ParseError.
Date literals are primarily useful in ranges.
const const literals: Type<{
singleQuoted: Date;
doubleQuoted: Date;
}>
literals = const type: TypeParser
<{
readonly singleQuoted: "d'01-01-1970'";
readonly doubleQuoted: "d\"01-01-1970\"";
}, Type<{
singleQuoted: Date;
doubleQuoted: Date;
}, {}>>(def: validateObjectLiteral<{
readonly singleQuoted: "d'01-01-1970'";
readonly doubleQuoted: "d\"01-01-1970\"";
}, {}, bindThis<...>>) => 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;
dateAfter2000: Date;
dateAtOrAfter1970: Date;
}>
bounded = const type: TypeParser
<{
readonly dateInThePast: `Date < ${number}`;
readonly dateAfter2000: "Date > d'2000-01-01'";
readonly dateAtOrAfter1970: "Date >= 0";
}, Type<{
dateInThePast: Date;
dateAfter2000: Date;
dateAtOrAfter1970: Date;
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
dateInThePast: `Date < ${Date.now()}`,
dateAfter2000: "Date > d'2000-01-01'",
dateAtOrAfter1970: "Date >= 0"
})
const const bounded: Type<{
dateInThePast: Date;
dateAfter2000: Date;
dateAtOrAfter1970: Date;
}>
bounded = const type: TypeParser
<{
readonly dateInThePast: Type<Date, {}>;
readonly dateAfter2000: Type<Date, {}>;
readonly dateAtOrAfter1970: Type<Date, {}>;
}, Type<{
dateInThePast: Date;
dateAfter2000: Date;
dateAtOrAfter1970: Date;
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
dateInThePast: type.Date.earlierThan(Date.now()),
dateAfter2000: type.Date.laterThan("2000-01-01"),
dateAtOrAfter1970: type.Date.atOrAfter(0)
})
Range expressions allow you to specify both a min and max and use the same syntax for exclusivity.
const const tenYearsAgo: number
tenYearsAgo = new Date()
.setFullYear(new Date().getFullYear() - 10)
.valueOf()
const const bounded: Type<{
dateInTheLast10Years: Date;
}>
bounded = const type: TypeParser
<{
readonly dateInTheLast10Years: `${number} <= Date < ${number}`;
}, Type<{
dateInTheLast10Years: Date;
}, {}>>(def: validateObjectLiteral<{
readonly dateInTheLast10Years: `${number} <= Date < ${number}`;
}, {}, bindThis<{
readonly dateInTheLast10Years: `${number} <= Date < ${number}`;
}>>) => Type<...> (+2 overloads)
type({
dateInTheLast10Years: `${const tenYearsAgo: number
tenYearsAgo} <= Date < ${Date.now()}`
})
const const tenYearsAgo: number
tenYearsAgo = new Date()
.setFullYear(new Date().getFullYear() - 10)
.valueOf()
const const bounded: Type<{
dateInTheLast10Years: Date;
}>
bounded = const type: TypeParser
<{
readonly dateInTheLast10Years: Type<Date, {}>;
}, Type<{
dateInTheLast10Years: Date;
}, {}>>(def: validateObjectLiteral<{
readonly dateInTheLast10Years: Type<Date, {}>;
}, {}, bindThis<...>>) => Type<...> (+2 overloads)
type({
dateInTheLast10Years: type.Date.atOrAfter(const tenYearsAgo: number
tenYearsAgo).earlierThan(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)
class MyClass {}
const const instances: Type<{
key: MyClass;
}>
instances = const type: TypeParser
<{
readonly key: readonly ["instanceof", typeof MyClass];
}, Type<{
key: MyClass;
}, {}>>(def: validateObjectLiteral<{
readonly key: readonly ["instanceof", typeof MyClass];
}, {}, bindThis<{
readonly key: readonly ["instanceof", typeof MyClass];
}>>) => Type<...> (+2 overloads)
type({
key: ["instanceof", MyClass]
})
class MyClass {}
const const instances: Type<{
key: MyClass;
}>
instances = const type: TypeParser
<{
readonly key: Type<MyClass, {}>;
}, Type<{
key: MyClass;
}, {}>>(def: validateObjectLiteral<{
readonly key: Type<MyClass, {}>;
}, {}, bindThis<{
readonly key: Type<MyClass, {}>;
}>>) => Type<...> (+2 overloads)
type({
key: const type: TypeParser
<"instanceof", typeof MyClass, readonly [], Type<MyClass, {}>>(_0: "instanceof", _1: typeof MyClass) => Type<MyClass, {}> (+2 overloads)
type("instanceof", MyClass)
})
keywords
🚧 Coming soon ™️🚧