https://github.com/junzhli/typescript-type-validator
Typescript-first type validator
https://github.com/junzhli/typescript-type-validator
Last synced: 4 days ago
JSON representation
Typescript-first type validator
- Host: GitHub
- URL: https://github.com/junzhli/typescript-type-validator
- Owner: junzhli
- Created: 2025-06-15T02:57:19.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-06-20T02:12:47.000Z (about 1 year ago)
- Last Synced: 2025-07-21T12:56:05.826Z (about 1 year ago)
- Language: TypeScript
- Size: 98.6 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Typescript type validator
[](https://www.npmjs.com/package/typescript-type-validator)
[](https://github.com/junzhli/typescript-type-validator/actions/workflows/build.yaml)
A fully TypeScript-supported type validator that enables type checks at both transpile time and runtime using a flexible schema and input validation.
## Features
* Type-Safe Schema Definition
* Automatic Type Inference
* Runtime Validation
* Nested Objects and Arrays
* Reusable Validators
* Flexible Validation Options (`ValidateOptions`)
* Custom Type Field Validation
## Installation
```shell
# yarn
yarn add typescript-type-validator
# npm
npm install typescript-type-validator
```
## Usage
### 1. Define a Schema
```typescript
import { field, objectField, arrayField, customField, Type, Validator, TypeFromSchema, FieldOptions } from "typescript-type-validator";
// Define a schema for your data
const userSchema = {
id: field(Type.Number), // required field (default)
name: field(Type.String), // required field (default)
email: field(Type.String, { optional: true }), // optional field
profile: objectField({
age: field(Type.Number), // required field
verified: field(Type.Bool, { optional: true }), // optional field
}),
tags: arrayField(field(Type.String)), // required array of strings
posts: arrayField(objectField({
title: field(Type.String),
content: field(Type.String),
published: field(Type.Bool, { optional: true }),
}), { optional: true }), // optional array of objects
// Custom field: must be a string that starts with "user_"
customId: customField((val) => {
if (typeof val !== "string" || !val.startsWith("user_")) throw new Error("customId must start with 'user_'");
return val as `user_${string}`;
}, { optional: true }),
} as const;
```
### 2. Get Inferred Type
```typescript
// TypeFromSchema gives you the TypeScript type for your schema
type User = TypeFromSchema;
// User is:
// {
// id: number;
// name: string;
// email?: string;
// profile: { age: number; verified?: boolean };
// tags: string[];
// posts?: { title: string; content: string; published?: boolean }[];
// customId?: `user_${string}`; // inferred from the custom field
// }
```
### 3. Validate Data at Runtime
```typescript
const userData = {
id: 1,
name: "Alice",
profile: { age: 30 },
tags: ["admin", "editor"],
};
const validated = Validator.validate(userSchema, userData);
// validated is now strongly typed as User
// Throws ValidationError if invalid:
try {
Validator.validate(userSchema, { id: "not-a-number", name: "Bob", profile: { age: 20 }, tags: [] });
} catch (e) {
console.error(e); // ValidationError with details
}
```
### 4. Use with Validation Options
```typescript
import { ValidateOptions } from "typescript-type-validator";
// Basic validation options
const options: ValidateOptions = {
strict: true, // throws on unexpected fields
rootKey: "request.body" // prefixes all error keys
};
const userData = {
id: 2,
name: "Charlie",
profile: { age: 25 },
tags: ["user"],
extra: "not allowed",
};
try {
Validator.validate(userSchema, userData, options);
} catch (e) {
console.error(e); // ValidationError: UnexpectedFieldError for key "request.body.extra"
}
// You can also use individual options
Validator.validate(userSchema, userData, { strict: true });
Validator.validate(userSchema, userData, { rootKey: "api.input" });
Validator.validate(userSchema, userData, {}); // default options
Validator.validate(userSchema, userData); // default options
```
### 5. Enhanced Error Context with Root Key
The `rootKey` option is particularly useful for API validation where you want to provide clear error paths:
```typescript
const apiSchema = {
user: objectField({
profile: objectField({
name: field(Type.String),
age: field(Type.Number),
})
})
};
try {
Validator.validate(apiSchema, {
user: { profile: { name: "John", age: "invalid" } }
}, { rootKey: "request.body" });
} catch (e) {
console.error(e.error.key); // "request.body.user.profile.age"
// Instead of just: "user.profile.age"
}
```
### 6. Use as a Class
```typescript
const userValidator = new Validator(userSchema);
// Same API as static method
const validUser = userValidator.validate({
id: 3,
name: "Dana",
profile: { age: 40, verified: true },
tags: [],
});
// With options
const validUserStrict = userValidator.validate(userData, { strict: true });
```
### 7. Custom Type Field Validation
You can define custom fields using your own resolver functions. The resolver receives the input value and must return the validated value. The return type will be inferred automatically.
```typescript
import { customField, Validator, TypeFromSchema } from "typescript-type-validator";
const schema = {
evenNumber: customField((val, key) => {
if (typeof val !== "number" || val % 2 !== 0) throw new Error(`Not an even number under key: ${key}`);
return val; // must return the original value
}),
optionalEvenNumber: customField((val, key) => {
if (typeof val !== "number" || val % 2 !== 0) throw new Error(`Not an even number under key: ${key}`);
return val;
}, { optional: true }),
};
type CustomType = TypeFromSchema;
// CustomType is: { evenNumber: number; optionalEvenNumber?: number }
Validator.validate(schema, { evenNumber: 4 }); // OK
Validator.validate(schema, { evenNumber: 3 }); // Throws error
```
## Field Options
All field functions (`field`, `objectField`, `arrayField`, `customField`) support the `FieldOptions` parameter:
```typescript
type FieldOptions = { optional?: boolean };
// Examples:
field(Type.String) // required (default)
field(Type.String, {}) // required (explicit)
field(Type.String, { optional: false }) // required (explicit)
field(Type.String, { optional: true }) // optional
objectField(schema) // required (default)
objectField(schema, { optional: true }) // optional
arrayField(innerField) // required (default)
arrayField(innerField, { optional: true }) // optional
customField(resolver) // required (default)
customField(resolver, { optional: true }) // optional
```
## Validation Options
The `ValidateOptions` type provides flexible validation configuration:
```typescript
type ValidateOptions = {
strict?: boolean; // Default: false - throws on unexpected fields when true
rootKey?: string; // Default: undefined - prefixes all error keys
};
// Usage examples:
Validator.validate(schema, data) // defaults
Validator.validate(schema, data, {}) // explicit defaults
Validator.validate(schema, data, { strict: true }) // strict mode only
Validator.validate(schema, data, { rootKey: "api.request" }) // error context only
Validator.validate(schema, data, { strict: true, rootKey: "body" }) // both options
```
---
**Exports available:**
- `field`, `objectField`, `arrayField`, `customField` — for schema definition
- `Type` — enum for field types
- `FieldOptions` — type for field configuration options
- `ValidateOptions` — type for validation configuration options
- `TypeFromSchema` — type inference from schema
- `Validator` — class and static method for validation