📖 Guide Documents⛲ Pure TypeScript

Pure TypeScript

Outline

assertArticle.ts
typia.assert<IBbsArticle>(article);

typia needs only one line with pure TypeScript type.

You know what? Every other validator libraries need extra schema definition, that is different with pure TypeScript type. For an example, class-validator is the most famous validator due to used in NestJS. However, NestJS and class-validator force you to define triple duplicated DTO schema.

  1. TypeScript Type
  2. class-validator decorators
  3. @nestjs/swagger decorators

Another famous validator library ajv requires JSON schema definition. Move to the #Demonstration, and click the ajv (JSON Schema) tab, then you may understand how it terrible. It requires hundreds of lines of JSON schema definition even just for a simple DTO.

Those duplicated schema definitions are not only annoying, but also error-prone. If you take any mistake on the extra schema definition, such mistake can’t be detected by TypeScript compiler. It will be detected only at runtime, therefore become a critical runtime error. Another words, it is not type safe.

Besides, typia only needs pure TypeScript type. You don’t need to define any extra schema like class-validator or ajv. Just define pure TypeScript type only (especially recommend to use interface type), then typia will do all the rest.

Demonstration

If you’re confusing how typia is different with others, just see example codes below.

At first, look at the first (class-validator) tab, and find the BbsArticle.files property, enhanced by blue coloured blocks. Looking at the files property, how do you feel? Just defining an array object type, you’ve to call 7 decorator functions. If you take any mistake when using the decorator like omitting isArray property, it would be a critical runtime erorr.

Besides, typia needs only one line. Click the third (typia) tab, and find the IAttachmentFile.files property. Only one line being used, and they are even not class, but just interface types. Comparing it to the first and second tabs, how do you feel? Isn’t it more simple and readable?

This is the power of typia, with pure TypeScript type.

BbsArticle.ts
import { ApiProperty } from "@nestjs/swagger";
import {
  ArrayNotEmpty,
  IsArray,
  IsObject,
  IsOptional,
  IsString,
  Match,
  MaxLength,
  Type,
  ValidateNested,
} from "class-validator";
 
export class BbsArticle {
  @ApiProperty({
    format: "uuid",
  })
  @IsString()
  id!: string;
 
  // DUPLICATED SCHEMA DEFINITION
  // - duplicated function call + property type
  // - have to specify `isArray` and `nullable` props by yourself
  @ApiProperty({
    type: () => AttachmentFile,
    nullable: true,
    isArray: true,
    description: "List of attached files.",
  })
  @Type(() => AttachmentFile)
  @IsArray()
  @IsOptional()
  @IsObject({ each: true })
  @ValidateNested({ each: true })
  files!: AttachmentFile[] | null;
 
  @ApiProperty({
    type: "string",
    nullable: true,
    minLength: 5,
    maxLength: 100,
    description: "Title of the article.",
  })
  @IsOptional()
  @IsString()
  title!: string | null;
 
  @ApiProperty({
    description: "Main content body of the article.",
  })
  @IsString()
  body!: string;
 
  @ApiProperty({
    format: "date-time",
    description: "Creation time of article",
  })
  @IsString()
  created_at!: string;
}
 
export class AttachmentFile {
  @ApiProperty({
    type: "string",
    maxLength: 255,
    pattern: "^[a-zA-Z0-9-_]+$",
    description: "File name.",
  })
  @Matches(/^[a-z0-9]+$/)
  @MaxLength(255)
  @IsString()
  name!: string | null;
 
  @ApiProperty({
    type: "string",
    nullable: true,
    maxLength: 255,
    pattern: "^[a-zA-Z0-9-_]+$",
    description: "File extension.",
  })
  @Matches(/^[a-z0-9]+$/)
  @MaxLength(8)
  @IsOptional()
  @IsString()
  extension!: string | null;
 
  @ApiProperty({
    format: "url",
    description: "URL of the file.",
  })
  @IsString()
  url!: string;
}

AOT Compilation

Someone may be suspicious of the phrase “Pure TypeScript Type”.

“As you know, TypeScript types do not have any tangible instance when compiled to JS.

However, with only these fictitious TypeScript types, how can typia validates types at runtime? How typia builds much faster JSON serializer only with these types? Are these things really possible without extra schema definition like class-validator or ajv?”

My answer is: “Yes, it is possible due to typia analyzes your server code, and performs AOT compilation”.

Such compile time optimization is called AOT (Ahead of Time) compilation. And this is the secret why typia can do everything with only pure TypeScript type. Read below example codes, and just look how JavaScript file being compiled. Then you may understand why typia is much easier, and futhermore much faster.

  • Runtime validator is 20,000x faster than class-validator
  • JSON serialization is 200x faster than class-transformer
assertArticle.ts
import typia from "typia";
 
import { IBbsArticle } from "./IBbsArticle";
 
export const assertArticle = typia.createAssert<IBbsArticle>();

Assert Function Benchmark

Measured on AMD Ryzen 9 7940HS, Rog Flow x13