Documentation chapters
Type

Types

Deepkit Type supports almost all TypeScript types out of the box. It could be a simple string, number, boolean, or more complex classes and interfaces, as well as computed types based on type functions like Partial, and even generics.

Since Deepkit Type uses the runtime type information made available by the type compiler of @deepkit/type-compiler, there is nothing special you have to write to make the types available in runtime.

How to use

On of the common use cases of deepkit type is casting data types. Serialization, validation, and database access are other use cases. All of them have in common that you pass the type as type argument to the function.

So, if you have for example a string type and want to convert or validate a string the code would look like that:

import { cast, is } from '@deepkit/type';

cast<string>(24); //becomes '24'
is<string>(24); //false
is<string>('24'); //true

interface User {
    id: number;
    username: string;
}

cast<User>({id: '24', username: 'Peter'}); //becomes {id: 24, username: 'Peter'}

is<User>({id: '24', username: 'Peter'}); //false
is<User>({id: 24, username: 'Peter'}); //true

Since the first type argument of cast could be any type, you could also write:

import { cast } from '@deepkit/type';

interface User {
    id: number;
    username: string;
}
cast<User['username']>(24); //becomes '24'

is<User>({id: 0}); //false
is<User>({id: , username: 'Peter'}); //true

is<Partial<User>>({id: 0}); //true

Or use other type functions.

import { cast } from '@deepkit/type';

interface User 
    id: string;
    createdAt: Date;
    username: string;
    firstName?: string;
    lastName?: string;
}

cast<Omit<User, 'id' | 'createdAt'>({username: 'Peter'}); //{username: 'Peter'}

//or use aliases
type UserCreate = Omit<User, 'id' | 'createdAt'>;
cast<UserCreate>({username: 'Peter'});
import { Maximum, Minimum } from '@deepkit/type';

type ID = number & Minimum<0> & Maximum<100>;

is<ID>(0); //true
is<ID>(120); //false

Special types

Deepkit Type comes with some special types as well as type annotations to enrich your types with additional information and behaviour.

Integer/Float

Using one of the integer/float types ensures during deserializing and validation that a value is in the correct range. The information is also available in runtime and allows for example Deepkit ORM to use the correct table column type.

import { cast, integer, int8, uint8 } from '@deepkit/type';

cast<integer>(12.4); //becomes 12
cast<integer>(12); //stays 12

cast<int8>(127); //stays 127
cast<int8>(233); //becomes 127

cast<uint8>(-12); //becomes 0
cast<uint8>(300); //becomes 255
import { validates, integer, uint8 } from '@deepkit/type';

validates<integer>(12); //true
validates<integer>(12.4); //false, since not an integer

validates<uint8>(420); //false, since max is 255
TypeDescription
integerAn integer of arbitrary size.
int8An integer between -128 and 127.
uint8An integer between 0 and 255.
int16An integer between -32768 and 32767.
uint16An integer between 0 and 65535.
int32An integer between -2147483648 and 2147483647.
uint32An integer between 0 and 4294967295.
floatSame as number, but might have different meaning in database context.
float32A float between -3.40282347e+38 and 3.40282347e+38. Note that JavaScript is not able to check correctly the range due to precision issues, but the information might be handy for the database or binary serializers.
float64Same as number, but might have different meaning in database context.

UUID

UUID v4 format. Can be combined with default value of uuid(). Deepkit ORM tries to save the UUID in a column type that is native to the database (usually as binary).

import { UUID, serialize, is, uuid } from '@deepkit/type';

serialize<UUID>('d06d7e9f-f229-479d-a1ee-67d17baa26d7'); //d06d7e9f-f229-479d-a1ee-67d17baa26d7
is<UUID>('d06d7e9f-f229-479d-a1ee-67d17baa26d7'); //true
is<UUID>('abcd'); //false

class User {
    id: UUID = uuid();
}

MongoId

Marks this field as ObjectId for MongoDB. Resolves as a string. Is stored in the MongoDB as binary.

import { MongoId, serialize, is } from '@deepkit/type';

serialize<MongoId>('507f1f77bcf86cd799439011'); //507f1f77bcf86cd799439011
is<MongoId>('507f1f77bcf86cd799439011'); //true
is<MongoId>('507f1f77bcf86cd799439011'); //false

class User {
    id: MongoId = ''; //will automatically set in Deepkit ORM once user is inserted
}

BinaryBigInt

Per default the normal bigint type serializes as number in JSON (and long in BSON). This has however limitation in what is possible to save as bigint in JavaScript has a unlimited potential size, where numbers in JavaScript and long in BSON are limited. To bypass this limitation the BinaryBigInt is available.

Same as bigint but serializes to unsigned binary with unlimited size (instead of 8 bytes in most databases) in databases and string in JSON. Negative values will be converted to positive (abs(x)).

import { BinaryBigInt } from '@deepkit/type';

interface User {
    id: BinaryBigInt;
}

const user: User = {id: 24n};

serialize<User>({id: 24n}); //{id: '24'}

serialize<BinaryBigInt>(24); //'24'
serialize<BinaryBigInt>(-24); //'0'

Deepkit ORM stores BinaryBigInt as a binary field.

SignedBinaryBigInt

Same as BinaryBigInt but is able to store negative values as well.

Deepkit ORM stores SignedBinaryBigInt as binary. The binary has an additional leading sign byte and is represented as an uint: 255 for negative, 0 for zero, or 1 for positive.

import { SignedBinaryBigInt } from '@deepkit/type';

interface User {
    id: SignedBinaryBigInt;
}

MapName

To change the name of a property in the serialization.

import { serialize, deserialize, MapName } from '@deepkit/type';

interface User {
    firstName: string & MapName<'first_name'>;
}

serialize<User>({firstName: 'Peter'}) // {first_name: 'Peter'}
deserialize<User>({first_name: 'Peter'}) // {firstName: 'Peter'}

Group

Properties can be grouped together. For serialization you can for example exclude a group from serialization. See the chapter Serialization for more information.

import { serialize } from '@deepkit/type';

interface Model {
    username: string;
    password: string & Group<'secret'>
}

serialize<Model>(
    { username: 'Peter', password: 'nope' },
    { groupsExclude: ['secret'] }
); //{username: 'Peter'}

Data

Each property can add additional meta data that can be read via the Reflection API.

import { ReflectionClass } from '@deepkit/type';

interface Model {
    username: string;
    title: string & Data<'key', 'value'>
}

const reflection = ReflectionClass.from<Model>();
reflection.getProperty('title').getData()['key']; //value;

Excluded

Each property can be excluded from the serialization process for a specific target.

import { serialize, deserialize, Excluded } from '@deepkit/type';

interface Auth {
    title: string;
    password: string & Excluded<'json'>
}

const item = deserialize<Auth>({title: 'Peter', password: 'secret'});

item.password; //undefined, since deserialize's default serializer is called `json`

item.password = 'secret';

const json = serialize<Auth>(item);
json.password; //again undefined, since serialize's serializer is called `json`

Entity

To annotate interfaces with entity information. Only used in the database context.

import { Entity, PrimaryKey } from '@deepkit/type';

interface User extends Entity<{name: 'user', collection: 'users'> {
    id: number & PrimaryKey;
    username: string;
}

PrimaryKey

Marks this field as primary key. Only used in the database context.

import { PrimaryKey } from '@deepkit/type';

interface User  {
    id: number & PrimaryKey;
    username: string;
}

AutoIncrement

Marks this field as auto increment. The field is usually also a primary key. Only used in the database context.

import { PrimaryKey, AutoIncrement } from '@deepkit/type';

interface User  {
    id: number & PrimaryKey & AutoIncrement;
    username: string;
}

Reference

Marks this field as a reference. Also known as Foreign Key in database context.

import { PrimaryKey, Reference } from '@deepkit/type';

interface Image {
    id: number & PrimaryKey;
    path: string;
    url: string;
}

interface User  {
    id: number & PrimaryKey;
    avatar: Image & Reference;
}

BackReference

Marks this field as a back reference. Needed for the reversed side of a reference.

import { PrimaryKey, Reference, BackReference } from '@deepkit/type';

interface Image {
    id: number & PrimaryKey;
    path: string;
    url: string;
    users: User[] & BackReference; 
}

interface User  {
    id: number & PrimaryKey;
    avatar: Image & Reference;
}

Index

Marks the field as an index.

import { PrimaryKey, Index } from '@deepkit/type';

interface User  {
    id: number & PrimaryKey;
    username: string & Index;
}

Unique

Marks the field as an unique index.

import { PrimaryKey, Unique } from '@deepkit/type';

interface User  {
    id: number & PrimaryKey;
    username: string & Unique;
}

Embedded

Marks the field as an embedded type.

import { PrimaryKey, Embedded, serialize, deserialize } from '@deepkit/type';

interface Address {
    street: string;
    postalCode: string;
    city: string;
    country: string;
}

interface User  {
    id: number & PrimaryKey;
    address: Embedded<Address>;
}

const user: User {
    id: 12,
    address: {
        street: 'abc', postalCode: '1234', city: 'Hamburg', country: 'Germany'
    }
};

serialize<User>(user);
{
    id: 12,
    address_street: 'abc',
    address_postalCode: '1234',
    address_city: 'Hamburg',
    address_country: 'Germany'
}

//for deserialize you have to provide the embedded structure
deserialize<User>({
    id: 12,
    address_street: 'abc',
    //...
});

It's possible to change the prefix (which is per default the property name).

interface User  {
    id: number & PrimaryKey;
    address: Embedded<Address, {prefix: 'addr_'}>;
}

serialize<User>(user);
{
    id: 12,
    addr_street: 'abc',
    addr_postalCode: '1234',
}

//or remove it entirely
interface User  {
    id: number & PrimaryKey;
    address: Embedded<Address, {prefix: ''}>;
}

serialize<User>(user);
{
    id: 12,
    street: 'abc',
    postalCode: '1234',
}

DatabaseField

This type allows to specify certain options to configure the database column/field definition. For example it enables you to define an explicit SQL database type, e.g. VARCHAr(255).

There are more specific versions of this type available via MySQL, Postgres, SQLite

import { MySQL, SQLite, DatabaseField } from '@deepkit/type';
        
class User {
    username: string & MySQL<{ type: 'varchar(255)' }> = '';
    username: string & SQLite<{ type: 'varchar(255)' }> = '';

    //same as above but for all databases
    username: string & DatabaseField<{ type: 'varchar(255)' }> = '';
}

InlineRuntimeType

This type allows to inject a dynamic built type object into the type system. The type processor includes the given variable content instead of inferring its type.

import { InlineRuntimeType, Type, ReflectionKind, typeOf, stringifyType } from '@deepkit/type';

const typeObject: Type = { kind: ReflectionKind.string };

interface MyType
    a: InlineRuntimeType<typeof typeObject>;
}

const type = typeOf<MyType>();

stringifyType(type); //MyType {a: string}

Explicit types

The type compiler only recognizes explicit type declarations, no inferring. That means if you want have types available in runtime make sure to explicitly define them. This is in most cases only necessary for class properties and function parameters.

class User {
    id = 0; //not typed
    id: number = 0; //correctly typed
}

Validation

To add additional validation checks there are several pre defined decorators available. To add custom validation functions and learn more about validation, see the chapter Validation.

Type decorationDescription
Validate<typeof myValidator>Custom validation function
Pattern<typeof myRegexp>Defines a regular expression as validation pattern. Usually used for E-Mail validation or more complex content validation.
AlphaValidation for alpha characters (a-Z).
AlphanumericValidation for alpha and numeric characters.
AsciiValidation for ASCII characters
Decimal<1, 34>Validation for string represents a decimal number, such as 0.1, .3, 1.1, 1.00003, 4.0, etc.
MultipleOf<3>Validation of numbers that are a multiple of given number.
MinLength<3>, MaxLength<4> Validation for min/max length for arrays or strings of given number.
Includes<'something'> Excludes<'something'> Validation for an array item being included/excluded.
Minimum<2>, Maximum<4>Validation for a value being minimum or maximum given number. Same as >=<=.
ExclusiveMinimum<3>, ExclusiveMaximum<3> Same as minimum/maximum but exludes the value itself. Same as ><
Positive, Negative, PositiveNoZero, NegativeNoZeroValidation for a value being positive or negative.
BeforeNow, AfterNowValidation for a date value compared to now (new Date).
EmailSimple regexp validation of emails via /^\S+@\S+$/.

More information about validators can be found in the chapter Validation

External classes

Since TypeScript does not include type information per default, imported types/classes from other packages (that did not use @deepkit/type-compiler) will not have type information available.

To annotate types for an external class, use annotateClass and make sure this function is executed in the bootstrap phase of your application before the imported class is used somewhere else.

import { MyExternalClass } from 'external-package';
import { annotateClass } from '@deepkit/type';

interface AnnotatedClass {
    id: number;
    title: string;
}

annotateClass<AnnotatedClass>(MyExternalClass);

//all uses of MyExternalClass return now the type of AnnotatedClass
serialize<MyExternalClass>({...});

//MyExternalClass can now also be used in other types
interface User {
    id: number;
    clazz: MyExternalClass;
}

MyExternalClass can now be used in serialization functions and in the reflection API.

To following shows how to annotate generic classes

import { MyExternalClass } from 'external-package';
import { annotateClass } from '@deepkit/type';
        
class AnnotatedClass<T> {
    id!: T;
}
        
annotateClass(ExternalClass, AnnotatedClass);

Not supported types

Not supported types are at the moment:
  1. Key remapping in Mapped Types, e.g. { [P in keyof T & string as `${P}Change`]: T[P] }
Made in Germany