import { Tabs, Tab } from 'nextra-theme-docs'
import Alert from '@mui/material/Alert';
import AlertTitle from '@mui/material/AlertTitle';
<Tabs items={[
typia
,
TypeGuardError.ts
,
]}>
export function assert<T>(input: T): T;
export function assert<T>(input: unknown): T;
```typescript
export class TypeGuardError extends Error {
public readonly method: string;
public readonly path: string | undefined;
public readonly expected: string;
public readonly value: any;
}
```
Asserts a value type.
typia.assert<T>()
function throws a TypeGuardError
when wrong type comes.
The TypeGuardError
instance has only the first type error info, with access path and expected type. In the below example case, as the age
property is wrong with its definition (@exclusiveMinimum
), such TypeGuardError
would be thrown:
method
: typia.assert()
path
: input.age
value
: 18
,
expected
: number & ExclusiveMinimum<19>
**AOT compliation**
If you'd used other competitive validator libraries like ajv
or class-validator
, you may found that typia
does not require any extra schema definition. If you have not experienced them, I can sure that you may get shocked after reading below extra schema definition files.
Yeah, typia
needs only pure TypeScript type. As typia
is a compiler library, it can analyze TypeScript type by itself, and possible to write the optimal validation code like below. This is the key principle of typia
, which needs only one line with pure TypeScript type.
<Tabs items={['TypeScript Source Code', 'Compiled JavaScript File']}>
import typia, { tags } from "typia";
import { v4 } from "uuid";
typia.assert<IMember>({
id: v4(),
email: "samchon.github@gmail.com",
age: 18, // wrong, must be greater than 19
});
interface IMember {
id: string & tags.Format<"uuid">;
email: string & tags.Format<"email">;
age: number &
tags.Type<"uint32"> &
tags.ExclusiveMinimum<19> &
tags.Maximum<100>;
}
```javascript filename="examples/bin/assert.js" showLineNumbers
"use strict";
var __importDefault =
(this && this.__importDefault) ||
function (mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const typia_1 = __importDefault(require("typia"));
const uuid_1 = require("uuid");
((input) => {
const __is = (input) => {
return (
"object" === typeof input &&
null !== input &&
"string" === typeof input.id &&
/^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(
input.id,
) &&
"string" === typeof input.email &&
/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(
input.email,
) &&
"number" === typeof input.age &&
Math.floor(input.age) === input.age &&
0 <= input.age &&
input.age <= 4294967295 &&
19 < input.age &&
input.age <= 100
);
};
if (false === __is(input))
((input, _path, _exceptionable = true) => {
const $guard = typia_1.default.assert.guard;
const $ao0 = (input, _path, _exceptionable = true) =>
(("string" === typeof input.id &&
(/^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(
input.id,
) ||
$guard(_exceptionable, {
path: _path + ".id",
expected: 'string & Format<"uuid">',
value: input.id,
}))) ||
$guard(_exceptionable, {
path: _path + ".id",
expected: '(string & Format<"uuid">)',
value: input.id,
})) &&
(("string" === typeof input.email &&
(/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(
input.email,
) ||
$guard(_exceptionable, {
path: _path + ".email",
expected: 'string & Format<"email">',
value: input.email,
}))) ||
$guard(_exceptionable, {
path: _path + ".email",
expected: '(string & Format<"email">)',
value: input.email,
})) &&
(("number" === typeof input.age &&
((Math.floor(input.age) === input.age &&
0 <= input.age &&
input.age <= 4294967295) ||
$guard(_exceptionable, {
path: _path + ".age",
expected: 'number & Type<"uint32">',
value: input.age,
})) &&
(19 < input.age ||
$guard(_exceptionable, {
path: _path + ".age",
expected: "number & ExclusiveMinimum<19>",
value: input.age,
})) &&
(input.age <= 100 ||
$guard(_exceptionable, {
path: _path + ".age",
expected: "number & Maximum<100>",
value: input.age,
}))) ||
$guard(_exceptionable, {
path: _path + ".age",
expected:
'(number & Type<"uint32"> & ExclusiveMinimum<19> & Maximum<100>)',
value: input.age,
}));
return (
((("object" === typeof input && null !== input) ||
$guard(true, {
path: _path + "",
expected: "IMember",
value: input,
})) &&
$ao0(input, _path + "", true)) ||
$guard(true, {
path: _path + "",
expected: "IMember",
value: input,
})
);
})(input, "$input", true);
return input;
})({
id: (0, uuid_1.v4)(),
email: "samchon.github@gmail.com",
age: 18, // wrong, must be greater than 19
});
```
<Tabs items={[
typia
,
TypeGuardError.ts
,
]}>
export function assertEquals<T>(input: T): T;
export function assertEquals<T>(input: unknown): T;
```typescript
export class TypeGuardError extends Error {
public readonly method: string;
public readonly path: string | undefined;
public readonly expected: string;
public readonly value: any;
}
```
More strict assert function prohibiting superfluous properties.
typia.assert<T>()
function inspects input
value type and throws TypeGuardError
when mismatched, however, it can't detect superfluous properties. If you want to prohibit those superfluous properties, therefore throws an TypeGuardError
when superfluous property exists, use typia.assertEquals<T()>
function instead.
In the below example case, as sex
property is not defined in the IMember
type, such TypeGuardError
would be thrown:
method
: typia.assertEquals()
path
: input.sex
value
: 1
,
expected
: undefined
<Tabs items={['TypeScript Source Code', 'Compiled JavaScript File']}>
import typia, { tags } from "typia";
import { v4 } from "uuid";
typia.assert<IMember>({
id: v4(),
email: "samchon.github@gmail.com",
age: 30,
sex: 1, // extra
});
interface IMember {
id: string & tags.Format<"uuid">;
email: string & tags.Format<"email">;
age: number &
tags.Type<"uint32"> &
tags.ExclusiveMinimum<19> &
tags.Maximum<100>;
}
```javascript filename="examples/bin/assertEquals.js" showLineNumbers
"use strict";
var __importDefault =
(this && this.__importDefault) ||
function (mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const typia_1 = __importDefault(require("typia"));
const uuid_1 = require("uuid");
((input) => {
const __is = (input) => {
return (
"object" === typeof input &&
null !== input &&
"string" === typeof input.id &&
/^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(
input.id,
) &&
"string" === typeof input.email &&
/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(
input.email,
) &&
"number" === typeof input.age &&
Math.floor(input.age) === input.age &&
0 <= input.age &&
input.age <= 4294967295 &&
19 < input.age &&
input.age <= 100
);
};
if (false === __is(input))
((input, _path, _exceptionable = true) => {
const $guard = typia_1.default.assert.guard;
const $ao0 = (input, _path, _exceptionable = true) =>
(("string" === typeof input.id &&
(/^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(
input.id,
) ||
$guard(_exceptionable, {
path: _path + ".id",
expected: 'string & Format<"uuid">',
value: input.id,
}))) ||
$guard(_exceptionable, {
path: _path + ".id",
expected: '(string & Format<"uuid">)',
value: input.id,
})) &&
(("string" === typeof input.email &&
(/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(
input.email,
) ||
$guard(_exceptionable, {
path: _path + ".email",
expected: 'string & Format<"email">',
value: input.email,
}))) ||
$guard(_exceptionable, {
path: _path + ".email",
expected: '(string & Format<"email">)',
value: input.email,
})) &&
(("number" === typeof input.age &&
((Math.floor(input.age) === input.age &&
0 <= input.age &&
input.age <= 4294967295) ||
$guard(_exceptionable, {
path: _path + ".age",
expected: 'number & Type<"uint32">',
value: input.age,
})) &&
(19 < input.age ||
$guard(_exceptionable, {
path: _path + ".age",
expected: "number & ExclusiveMinimum<19>",
value: input.age,
})) &&
(input.age <= 100 ||
$guard(_exceptionable, {
path: _path + ".age",
expected: "number & Maximum<100>",
value: input.age,
}))) ||
$guard(_exceptionable, {
path: _path + ".age",
expected:
'(number & Type<"uint32"> & ExclusiveMinimum<19> & Maximum<100>)',
value: input.age,
}));
return (
((("object" === typeof input && null !== input) ||
$guard(true, {
path: _path + "",
expected: "IMember",
value: input,
})) &&
$ao0(input, _path + "", true)) ||
$guard(true, {
path: _path + "",
expected: "IMember",
value: input,
})
);
})(input, "$input", true);
return input;
})({
id: (0, uuid_1.v4)(),
email: "samchon.github@gmail.com",
age: 30,
sex: 1, // extra
})
```
<Tabs items={[
typia
,
TypeGuardError.ts
,
]}>
export function assertGurad<T>(input: T): asserts inut is T;
export function assertGuard<T>(input: unknown): asserts input is T;
export function assertGuardEquals<T>(input: T): asserts inut is T;
export function assertGuardEquals<T>(input: unknown): asserts input is T;
```typescript
export class TypeGuardError extends Error {
public readonly method: string;
public readonly path: string | undefined;
public readonly expected: string;
public readonly value: any;
}
```
Assertion guard of a value type.
typia.assertGuard<T>()
is similar with typia.assert<T>()
throwing a TypeGuardError
when wrong type.
However, typia.assert<T>()
returns the paramteric input value itself when there's no type problem on the parametric input value, whereas the typia.assertGuard<T>()
function returns nothing. Instead, the parametric input value would be automatically cased to the type T
. This is the concept of "Assertion Guard" of a value type.
Such similarities and differences of typia.assertGuard<T>()
and typia.assert<T>()
functions are the same in the case of typia.assertGuardEquals<T>()
and typia.assertEquals<T>()
functions. If there's no type problem on the typia.assertGuardEquals<T>()
function, it also performs the "Assertion Guard".
Look at the below code, then you may understand what the "Assertion Guard" means.
import typia from "typia";
interface IPoint {
x: number;
y: number;
}
const input: unknown = { x: 1, y: 2 };
// PERFORM THE ASSERTION GUARD
typia.assertGuard<IPoint>(input);
// FROM NOW ON, "input" IS THE "IPoint" TYPE
input.x; // OK
input.y; // OK
<Tabs items={[
typia
,
TypeGuardError.ts
,
AssertionGuard.ts
,
]}>
export function createAssert<T>(): (input: unknown) => T;
export function createAssertEquals<T>(): (input: unknown) => T;
export function createAssertGuard<T>(): AssertionGuard<T>;
export function createAssertGuardEquals<T>(): AssertionGuard<T>;
```typescript
export class TypeGuardError extends Error {
public readonly method: string;
public readonly path: string | undefined;
public readonly expected: string;
public readonly value: any;
}
```
```typescript
export type AssertionGuard = (input: unknown) => asserts input is T;
```
Reusable typia.assert<T>()
function generators.
If you repeat to call typia.assert<T>()
function on the same type, size of JavaScript files would be larger because of duplicated AOT compilation. To prevent it, you can generate reusable function through typia.createAssert<T>()
function.
Just look at the code below, then you may understand how to use it.
<Tabs items={['TypeScript Source Code', 'Compiled JavaScript File']}>
import typia, { tags } from "typia";
export const assertMember = typia.createAssert<IMember>();
interface IMember {
id: string & tags.Format<"uuid">;
email: string & tags.Format<"email">;
age: number &
tags.Type<"uint32"> &
tags.ExclusiveMinimum<19> &
tags.Maximum<100>;
}
```javascript filename="examples/bin/createAssert.js" showLineNumbers
"use strict";
var __importDefault =
(this && this.__importDefault) ||
function (mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.assertMember = void 0;
const typia_1 = __importDefault(require("typia"));
const assertMember = (input) => {
const __is = (input) => {
return (
"object" === typeof input &&
null !== input &&
"string" === typeof input.id &&
/^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(
input.id,
) &&
"string" === typeof input.email &&
/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(
input.email,
) &&
"number" === typeof input.age &&
Math.floor(input.age) === input.age &&
0 <= input.age &&
input.age <= 4294967295 &&
19 < input.age &&
input.age <= 100
);
};
if (false === __is(input))
((input, _path, _exceptionable = true) => {
const $guard = typia_1.default.createAssert.guard;
const $ao0 = (input, _path, _exceptionable = true) =>
(("string" === typeof input.id &&
(/^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(
input.id,
) ||
$guard(_exceptionable, {
path: _path + ".id",
expected: 'string & Format<"uuid">',
value: input.id,
}))) ||
$guard(_exceptionable, {
path: _path + ".id",
expected: '(string & Format<"uuid">)',
value: input.id,
})) &&
(("string" === typeof input.email &&
(/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(
input.email,
) ||
$guard(_exceptionable, {
path: _path + ".email",
expected: 'string & Format<"email">',
value: input.email,
}))) ||
$guard(_exceptionable, {
path: _path + ".email",
expected: '(string & Format<"email">)',
value: input.email,
})) &&
(("number" === typeof input.age &&
((Math.floor(input.age) === input.age &&
0 <= input.age &&
input.age <= 4294967295) ||
$guard(_exceptionable, {
path: _path + ".age",
expected: 'number & Type<"uint32">',
value: input.age,
})) &&
(19 < input.age ||
$guard(_exceptionable, {
path: _path + ".age",
expected: "number & ExclusiveMinimum<19>",
value: input.age,
})) &&
(input.age <= 100 ||
$guard(_exceptionable, {
path: _path + ".age",
expected: "number & Maximum<100>",
value: input.age,
}))) ||
$guard(_exceptionable, {
path: _path + ".age",
expected:
'(number & Type<"uint32"> & ExclusiveMinimum<19> & Maximum<100>)',
value: input.age,
}));
return (
((("object" === typeof input && null !== input) ||
$guard(true, {
path: _path + "",
expected: "IMember",
value: input,
})) &&
$ao0(input, _path + "", true)) ||
$guard(true, {
path: _path + "",
expected: "IMember",
value: input,
})
);
})(input, "$input", true);
return input;
};
exports.assertMember = assertMember;
```
**Explicity of Assertion Guard**
Be careful when using typia.createAssertGuard<T>()
or typia.createAssertGuardEquals<T>()
functions.
When calling those functions, you've to declare the variable type explicit on the caller variable. If you don't do it, so that the caller variables come the implicit function type, TypeScript compiler throws an error like below. This is a special limitation of TypeScript compiler about the "Assertion Guard".
import typia, { AssertionGuard } from "typia";
//MUST DECLARE THE VARIABLE TYPE
const explicit: AssertionGuard<number> = typia.createAssertGuard<number>();
// IF NOT, COMPILATION ERROR BE OCCURED
const implicit = typia.createAssertGuard<number>();
Assertions require every name in the call target to be declared with an explicit type annotation.
typia.assert<T>()
function does not check function
and user-defined class
types.
It validates only the primitive properties. Therefore, typia.assert<T>()
function does not perform the instanceof ClassName
for user-defined classes. If you want to validate the user-defined class type in addition to the property types, do it by yourself. Also, typia.assert<T>()
function does not validate the function type either, unless configuring functional
property of plugin
option in the tsconfig.json
file.
{
"compilerOptions": {
"plugins": [
{
"transform": "typia/lib/transform",
"functional": true
}
]
}
}
By the way, there're some exception cases.
If JS native class type like Date
, Uint8Array
, or Map<Key, T>
being utilized, typia.assert<T>()
function validates them. Especially about the Set<T>
, and Map<Key, T>
class cases, typia.assert<T>()
function validates all of their contained element types, too.
Therefore, the instanceof
statement does not be used only for the user-defined classes.
<Tabs items={['TypeScript Source Code', 'Compiled JavaScript File']}>
import typia from "typia";
typia.createIs<Map<string, boolean | number | string>>();
```javascript filename="examples/bin/is-map.js" showLineNumbers
"use strict";
var __importDefault =
(this && this.__importDefault) ||
function (mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const typia_1 = __importDefault(require("typia"));
(input) => {
return (
input instanceof Map &&
(() =>
[...input].every(
(elem) =>
Array.isArray(elem) &&
elem.length === 2 &&
"string" === typeof elem[0] &&
("string" === typeof elem[1] ||
"number" === typeof elem[1] ||
"boolean" === typeof elem[1]),
))()
);
};
```
You can enhance validation logic by special tags.
Also, with those tags, you can add your custom validation logic, too.
If you want to know about such special tags detaily, read below article:
<Tabs items={['TypeScript Source Code', 'Compiled JavaScript File']}>
import typia, { tags } from "typia";
export const assertSomething = typia.createAssert<Something>();
//----
// DEFINE CUSTOM TYPE TAGS
//----
type Dollar = tags.TagBase<{
kind: "dollar";
target: "string";
value: undefined;
validate: `$input[0] === "$" && !isNaN(Number($input.substring(1).split(",").join("")))`;
}>;
type Postfix<Value extends string> = tags.TagBase<{
kind: "postfix";
target: "string";
value: Value;
validate: `$input.endsWith("${Value}")`;
}>;
type IsEven<Value extends number | bigint> = tags.TagBase<{
kind: "isEven";
target: Value extends number ? "number" : "bigint";
value: undefined;
validate: `$input % ${Numeric<2>} === ${Numeric<0>}`;
}>;
type Numeric<Value extends number | bigint> = Value extends number
? Value
: `BigInt(${Value})`;
//----
// VALIDATION
//----
interface Something {
dollar: string & Dollar;
postfix: string & Postfix<"!!!">;
isEven: number & IsEven<number>;
}
```javascript filename="examples/bin/assert-custom-tags.js" showLineNumbers
"use strict";
var __importDefault =
(this && this.__importDefault) ||
function (mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.assertSomething = void 0;
const typia_1 = __importDefault(require("typia"));
const assertSomething = (input) => {
const __is = (input) => {
return (
"object" === typeof input &&
null !== input &&
"string" === typeof input.dollar &&
input.dollar[0] === "$" &&
!isNaN(Number(input.dollar.substring(1).split(",").join(""))) &&
"string" === typeof input.postfix &&
input.postfix.endsWith("!!!") &&
"number" === typeof input.isEven &&
input.isEven % 2 === 0
);
};
if (false === __is(input))
((input, _path, _exceptionable = true) => {
const $guard = typia_1.default.createAssert.guard;
const $ao0 = (input, _path, _exceptionable = true) =>
(("string" === typeof input.dollar &&
((input.dollar[0] === "$" &&
!isNaN(Number(input.dollar.substring(1).split(",").join("")))) ||
$guard(_exceptionable, {
path: _path + ".dollar",
expected: "string & Dollar",
value: input.dollar,
}))) ||
$guard(_exceptionable, {
path: _path + ".dollar",
expected: "(string & Dollar)",
value: input.dollar,
})) &&
(("string" === typeof input.postfix &&
(input.postfix.endsWith("!!!") ||
$guard(_exceptionable, {
path: _path + ".postfix",
expected: 'string & Postfix<"!!!">',
value: input.postfix,
}))) ||
$guard(_exceptionable, {
path: _path + ".postfix",
expected: '(string & Postfix<"!!!">)',
value: input.postfix,
})) &&
(("number" === typeof input.isEven &&
(input.isEven % 2 === 0 ||
$guard(_exceptionable, {
path: _path + ".isEven",
expected: "number & IsEven",
value: input.isEven,
}))) ||
$guard(_exceptionable, {
path: _path + ".isEven",
expected: "(number & IsEven)",
value: input.isEven,
}));
return (
((("object" === typeof input && null !== input) ||
$guard(true, {
path: _path + "",
expected: "Something",
value: input,
})) &&
$ao0(input, _path + "", true)) ||
$guard(true, {
path: _path + "",
expected: "Something",
value: input,
})
);
})(input, "$input", true);
return input;
};
exports.assertSomething = assertSomething;
```
Super-fast and super-safe.
Comparing typia.assert<T>()
function with other competitive libraries, maximum 20,000x faster.
Furthermore, only typia
can validate complicate union types.
Measured on Intel i5-1135g7, Surface Pro 8
C.V.
means class-validator