Unlock Runtime TypeScript Types with DeepKit for Validation and Serialization

This article introduces DeepKit, a TypeScript library that preserves type information at runtime, enabling powerful data validation, serialization, and reflection capabilities for both front‑end and back‑end JavaScript applications.

ELab Team
ELab Team
ELab Team
Unlock Runtime TypeScript Types with DeepKit for Validation and Serialization

Background

Earlier we investigated a TypeScript data validation solution and discovered the third‑party library DeepKit, which can retain TypeScript type information at runtime.

What TypeScript Brings

Traditional JavaScript provides no type safety; TypeScript adds static type checking, but its type information is erased during compilation, leaving no runtime overhead.

However, runtime type information can be valuable in many scenarios.

Why Runtime Types Are Needed

Two typical scenarios:

Data Validation

When implementing an API or writing to a database, the incoming data must be validated against the expected type definitions.

Service parameters may be arbitrary; without validation the code can crash.

Database fields have strict types; data must conform before insertion.

Serialization / Deserialization

JSON.parse/stringify lose type fidelity for complex objects such as Date.

const date = new Date();
const dateString = JSON.stringify(date); // "2022-11-02T17:49:03.240Z"
const dateJson = JSON.parse(dateString); // "2022-11-02T17:49:03.240Z"

DeepKit makes preserving TypeScript types at runtime possible.

Quick Start

Official docs: https://deepkit.io/

Prerequisites

Install two packages:

@deepkit/type – runtime utilities

@deepkit/type-compiler – type compiler to be added to devDependencies in package.json

npm install --save @deepkit/type
npm install --save-dev @deepkit/type-compiler

Enable reflection in tsconfig.json and, if needed, experimentalDecorators.

// tsconfig.json
{
  "compilerOptions": {
    "module": "CommonJS",
    "target": "es6",
    "moduleResolution": "node",
    "experimentalDecorators": true
  },
  "reflection": true
}

Type Information

Type Objects

Use typeOf to obtain a type object.

import { typeOf } from '@deepkit/type';
type Title<T> = T extends true ? string : number;
typeOf<Title<true>>();
// Type {kind: 5, typeName: 'Title', typeArguments: [{kind: 7}]}

Key fields: kind, typeName, typeArguments.

enum ReflectionKind {
  never, any, unknown, void, object, string, number, boolean, symbol, bigint,
  null, undefined
}

Reflection Classes

Useful for complex types such as classes or interfaces.

import { ReflectionClass } from '@deepkit/type';
interface User { id: number; username: string; }
const reflection = ReflectionClass.from<User>();
reflection.getProperty('id'); // ReflectionProperty with type info

Validation

DeepKit provides is and validate functions.

interface People { name: string; age: number; info?: { address?: string; phone: number } }
const peopleA = { name: 'Jack', age: 20 };
const peopleB = { name: 'Peter', age: 18, info: {} };
is<People>(peopleA); // true
is<People>(peopleB); // false
validate<People>(peopleA); // []
validate<People>(peopleB); // [{path: 'info.phone', code: 'type', message: 'Not a number'}]

Serialization

Use serialize and deserialize to keep type fidelity.

import { serialize, deserialize } from '@deepkit/type';
class MyModel { id = 0; created = new Date(); constructor(public name: string) {} }
const model = new MyModel('Peter');
const jsonObject = serialize<MyModel>(model);
// { id: 0, created: '2022-11-02T17:49:03.240Z', name: 'Peter' }
const myModel = deserialize<MyModel>({ id: 5, created: 'Sat Oct 13 2018 14:17:35 GMT+0200', name: 'Peter' });
is<Date>(myModel.created); // true

Type Decorators

DeepKit offers decorators such as integer, PrimaryKey, maxLength, etc., extending TypeScript types for database‑level constraints.

import { integer } from '@deepkit/type';
type count = integer;
is<count>(1); // true
is<count>(1.1); // false

Performance Optimizations

Type Caching

Non‑generic type objects are cached, while generic ones are not.

type MyType = string;
typeOf<MyType>() === typeOf<MyType>(); // true

type MyType<T> = T;
typeOf<MyType<string>>() === typeOf<MyType<string>>(); // false

Type Compiler

The compiler injects bytecode into the TypeScript AST, which a tiny VM executes at runtime to produce type objects.

More Capabilities

Event system: @deepkit/events

HTTP library: @deepkit/http

RPC services: @deepkit/rpc

ORM: @deepkit/orm

Template engine: @deepkit/templ (incompatible with React)

Full‑stack framework: @deepkit/framework

Conclusion

DeepKit is the first solution that provides a complete set of runtime TypeScript types for JavaScript, enabling shared data models between front‑end and back‑end and a reflection mechanism built on TypeScript.

Limitations include lack of support for external types that are not processed by the DeepKit compiler.

Official site: https://deepkit.io/

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

TypeScriptReflectionNode.jsserializationvalidationDeepKitruntime types
ELab Team
Written by

ELab Team

Sharing fresh technical insights

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.