API
Keywords
const const keywords: Type<{
string: string;
date: Date;
dateFormattedString: string.date;
isoFormattedString: string.date.iso;
transformStringToDate: (In: string.date) => To<Date>;
}>
keywords = const type: TypeParser
<{
readonly string: "string";
readonly date: "Date";
readonly dateFormattedString: "string.date";
readonly isoFormattedString: "string.date.iso";
readonly transformStringToDate: "string.date.parse";
}, Type<...>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
string: "string",
date: "Date",
// Subtype keywords refine or transform their root type.
dateFormattedString: "string.date",
isoFormattedString: "string.date.iso",
transformStringToDate: "string.date.parse"
})
const const keywords: Type<{
string: string;
date: Date;
dateFormattedString: string.date;
isoFormattedString: string.date.iso;
transformStringToDate: (In: string.date) => To<Date>;
}>
keywords = const type: TypeParser
<{
readonly string: Type<string, {}>;
readonly date: Type<Date, Ark>;
readonly dateFormattedString: Type<string.date, Ark>;
readonly isoFormattedString: Type<...>;
readonly transformStringToDate: Type<...>;
}, Type<...>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
// Primitive keywords are exposed directly on `type`.
string: type.string,
// All builtin keywords and modules are available under `keywords`.
date: type.keywords.Date,
// Subtype keywords refine or transform their root type.
// `.root` gets the base type of a subtyped module.
dateFormattedString: type.keywords.string.date.root,
isoFormattedString: type.keywords.string.date.iso.root,
transformStringToDate: type.keywords.string.date.parse
})
Literals
const const literals: Type<{
number: 1337;
bigint: 1337n;
string: {
singleQuoted: "typescript";
doubleQuoted: "arktype";
};
date: {
singleQuoted: Date.literal<"01-01-1970">;
doubleQuoted: Date.literal<"01-01-1970">;
};
keywords: [true, false, null, undefined];
}>
literals = const type: TypeParser
<{
readonly number: "1337";
readonly bigint: "1337n";
readonly string: {
readonly singleQuoted: "'typescript'";
readonly doubleQuoted: "\"arktype\"";
};
readonly date: {
readonly singleQuoted: "d'01-01-1970'";
readonly doubleQuoted: "d\"01-01-1970\"";
};
readonly keywords: readonly [...];
}, Type<...>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
number: "1337",
bigint: "1337n",
string: {
singleQuoted: "'typescript'",
doubleQuoted: '"arktype"'
},
date: {
// Date literals represent a Date instance with an exact value.
// They're primarily useful in ranges (see below).
singleQuoted: "d'01-01-1970'",
doubleQuoted: 'd"01-01-1970"'
},
keywords: ["true", "false", "null", "undefined"]
})
// `type.unit` creates a type that allows exactly one value (according to ===)
const const exactValue: Type<1337>
exactValue = type.unit(1337)
// `type.enumerated` creates a type that allows a set of values (according to ===)
const const exactValueFromSet: Type<true | 1337 | null>
exactValueFromSet = type.enumerated(1337, true, null)
Objects
const const symbolicKey: typeof symbolicKey
symbolicKey = Symbol()
const const object: Type<{
[x: string]: string;
requiredKey: string;
[symbolicKey]: {
nested: unknown;
};
optionalKey?: string.uuid;
}>
object = const type: TypeParser
<{
readonly requiredKey: "string";
readonly "optionalKey?": "string.uuid";
readonly [symbolicKey]: {
readonly nested: "unknown";
};
readonly "[string]": "string";
}, Type<{
[x: string]: string;
requiredKey: string;
[symbolicKey]: {
...;
};
optionalKey?: string.uuid;
}, {}>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
requiredKey: "string",
"optionalKey?": "string.uuid",
// Nested definitions don't require additional `type` calls.
[const symbolicKey: typeof symbolicKey
symbolicKey]: {
nested: "unknown"
},
// Index signatures are unlabeled and support arbitrary expressions.
"[string]": "string"
})
Kitchen Sink (more comprehensive docs to come next week!)
export const const currentTsSyntax: Type<{
keyword: null;
stringLiteral: "TS";
numberLiteral: 5;
bigintLiteral: 5n;
union: string | number;
intersection: true;
array: Date[];
grouping: (0 | 1)[];
objectLiteral: {
nested: string;
optional?: number;
};
arrayOfObjectLiteral: {
name: string;
}[];
tuple: [number, number];
keyof: never;
variadicTuples: [true, ...false[]];
arrayOfObjectLiteralChained: {
name: string;
}[];
}>
currentTsSyntax = const type: TypeParser
<{
readonly keyword: "null";
readonly stringLiteral: "'TS'";
readonly numberLiteral: "5";
readonly bigintLiteral: "5n";
readonly union: "string|number";
readonly intersection: "boolean&true";
... 7 more ...;
readonly arrayOfObjectLiteralChained: Type<...>;
}, Type<...>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
keyword: "null",
stringLiteral: "'TS'",
numberLiteral: "5",
bigintLiteral: "5n",
union: "string|number",
intersection: "boolean&true",
array: "Date[]",
grouping: "(0|1)[]",
objectLiteral: {
nested: "string",
"optional?": "number"
},
arrayOfObjectLiteral: [
{
name: "string"
},
"[]"
],
tuple: ["number", "number"],
keyof: "keyof object",
variadicTuples: ["true", "...", "false[]"],
arrayOfObjectLiteralChained: const type: TypeParser
<{
readonly name: "string";
}, Type<{
name: string;
}, {}>>(def: validateObjectLiteral<{
readonly name: "string";
}, {}, bindThis<{
readonly name: "string";
}>>) => Type<...> (+2 overloads)
type({ name: "string" }).array()
})
Constraints
// runtime-specific syntax and builtin keywords with great error messages
export const const validationSyntax: Type<{
keywords: string.email | string.uuid | string.creditCard | integer;
builtinParsers: (In: string.date) => To<Date>;
nativeRegexLiteral: string.matching<string>;
embeddedRegexLiteral: of<string, Predicate<"email"> & Matching<"@arktype\\.io">>;
divisibility: number.divisibleBy<10>;
bound: string.is<MoreThanLength<10> & Predicate<"alpha">>;
range: of<string.email[], LessThanLength<100> & AtLeastLength<1>>;
narrows: number.branded<"?">;
morphs: (In: string) => Out<number>;
}>
validationSyntax = const type: TypeParser
<{
readonly keywords: "string.email | string.uuid | string.creditCard | number.integer";
readonly builtinParsers: "string.date.parse";
readonly nativeRegexLiteral: RegExp;
... 5 more ...;
readonly morphs: readonly [...];
}, Type<...>>(def: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({
keywords: "string.email | string.uuid | string.creditCard | number.integer", // and many more
builtinParsers: "string.date.parse", // parses a Date from a string
nativeRegexLiteral: /@arktype\.io/,
embeddedRegexLiteral: "string.email & /@arktype\\.io/",
divisibility: "number % 10", // a multiple of 10
bound: "string.alpha > 10", // an alpha-only string with more than 10 characters
range: "1 <= string.email[] < 100", // a list of 1 to 99 emails
narrows: ["number", ":", n => n % 2 === 1], // an odd integer
morphs: ["string", "=>", parseFloat] // validates a string input then parses it to a number
})
// root-level expressions
const const intersected: Type<{
value: string;
format: "bigint";
}>
intersected = const type: TypeParser
<{
readonly value: "string";
}, "&", readonly [{
readonly format: "'bigint'";
}], Type<{
value: string;
format: "bigint";
}, {}>>(_0: validateObjectLiteral<{
readonly value: "string";
}, {}, bindThis<{
readonly value: "string";
}>>, _1: "&", _2_0: validateObjectLiteral<...>) => Type<...> (+2 overloads)
type({ value: "string" }, "&", { format: "'bigint'" })
// chained expressions via .or, .and, .narrow, .pipe and much more
// (these replace previous helper methods like union and intersection)
const const user: Type<{
name: string;
age: number;
}>
user = const type: TypeParser
<{
readonly name: "string";
readonly age: "number";
}, Type<{
name: string;
age: number;
}, {}>>(def: validateObjectLiteral<{
readonly name: "string";
readonly age: "number";
}, {}, bindThis<{
readonly name: "string";
readonly age: "number";
}>>) => Type<...> (+2 overloads)
type({
name: "string",
age: "number"
})
// type is fully introspectable and traversable
const const parseUser: Type<(In: string) => To<{
name: string;
age: number;
}>>
parseUser = const type: TypeParser
<"string", Type<string, {}>>(def: "string") => Type<string, {}> (+2 overloads)
type("string").pipe(s => JSON.parse(s), const user: Type<{
name: string;
age: number;
}>
user)
const const maybeMe: ArkErrors | {
name: string;
age: number;
}
maybeMe = parseUser('{ "name": "David" }')
if (const maybeMe: ArkErrors | {
name: string;
age: number;
}
maybeMe instanceof type.errors) {
// "age must be a number (was missing)"
console.log(const maybeMe: ArkErrors
maybeMe.summary)
}