JSPM

  • Created
  • Published
  • Downloads 22
  • Score
    100M100P100Q60562F
  • License MIT

Advanced TypeScript type guard generator with sophisticated recursion detection, enhanced enum handling, and comprehensive utility support using guardz 1.10.3 library

Package Exports

  • guardz-generator
  • guardz-generator/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (guardz-generator) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Guardz Generator

GitHub Sponsors

Guardz Generator is a powerful tool for automatically generating runtime type guards from your TypeScript interfaces and type aliases, using the guardz library. It enables robust runtime type checking for your TypeScript codebase with minimal effort.

What Can Guardz Generator Do?

  • Generate Type Guards: Automatically creates type guard functions for your TypeScript interfaces, type aliases, enums, and more.
  • Supports Generics: Handles generic interfaces and type aliases, including nested generics.
  • Handles Recursion: Detects and supports both direct and indirect recursive types, generating correct function-based guards.
  • Advanced Enum Support: Generates guards for enums using the isEnum() pattern.
  • Union & Composite Types: Supports union types, intersection types, and complex compositions.
  • Interface Extensions: Correctly handles interface inheritance with isExtensionOf and Omit types, properly filtering inherited properties.
  • Cross-file & NPM Types: Resolves and generates guards for types imported from other files or npm packages, using local guards when available or falling back to isAsserted.
  • Smart Import Path Resolution: Maintains consistency with your original import structure:
    • Preserves relative imports: './models/User''./models/User.guardz'
    • Respects path aliases: '@/types/ApiResponse''@/types/ApiResponse.guardz'
    • Handles global imports: '@/global/_GlobalTypesToImport''@/global/isTypeName.guardz'
  • Post-Processing: Optionally formats, lints, and type-checks generated files for code quality.
  • Flexible CLI & API: Use via CLI or programmatically in your own scripts.
  • Full guardz 1.10.3 Support: Includes all utilities and enhanced error handling with comprehensive type checking capabilities.

Guardz Version Compatibility

Guardz Generator is fully compatible with guardz 1.10.3 and includes support for all features:

Core Type Guards

  • isString, isNumber, isBoolean, isDate: Basic type validation
  • isAny, isUnknown: Universal type guards
  • isDefined, isNil: Null/undefined checking
  • isEnum: Enum validation

Advanced Type Guards

  • isType: Object structure validation
  • isObjectWith: Object property validation
  • isObject: Object type checking
  • isPartialOf: Partial object validation
  • isNonNullObject: Non-null object validation
  • isExtensionOf: Interface inheritance validation
  • isIntersectionOf: Intersection type validation

Array & Collection Guards

  • isArrayWithEachItem: Array element validation
  • isNonEmptyArray: Non-empty array validation
  • isNonEmptyArrayWithEachItem: Non-empty array with element validation
  • isTuple: Tuple validation
  • isMap: Map validation
  • isSet: Set validation

Number Guards

  • isInteger, isBigInt: Integer validation
  • isPositiveNumber, isNegativeNumber: Sign validation
  • isPositiveInteger, isNegativeInteger: Integer sign validation
  • isNonNegativeNumber, isNonPositiveNumber: Non-negative/non-positive validation
  • isNonNegativeInteger, isNonPositiveInteger: Integer range validation

String Guards

  • isNonEmptyString: Non-empty string validation
  • isEqualTo: Equality validation

Union & Optional Guards

  • isOneOf: Union type validation
  • isOneOfTypes: Multiple type validation
  • isUndefinedOr, isNullOr, isNilOr: Optional type validation

Web API Guards

  • isFileList: FileList validation
  • isBlob: Blob validation
  • isFormData: FormData validation
  • isURL: URL validation
  • isURLSearchParams: URLSearchParams validation
  • isFile: File validation

Function & Error Guards

  • isFunction: Function validation
  • isError: Error validation

Advanced Features

  • guardWithTolerance: Tolerance-based validation
  • isAsserted: Type assertion for external types
  • generateTypeGuardError: Enhanced error messages

Example Usage

export interface AdvancedUser {
  id: number;
  name: string;
  email: string;
  files: FileList;
  metadata: Map<string, unknown>;
  errors: Error[];
  settings: Partial<{ theme: string; notifications: boolean }>;
}

Generated:

import type { AdvancedUser } from './_AdvancedUser';
import type { TypeGuardFn } from 'guardz';
import {
  isString,
  isNumber,
  isFileList,
  isMap,
  isArrayWithEachItem,
  isError,
  isPartialOf,
  isType,
} from 'guardz';

export const isAdvancedUser: TypeGuardFn<AdvancedUser> = isType<AdvancedUser>({
  id: isNumber,
  name: isString,
  email: isString,
  files: isFileList,
  metadata: isMap,
  errors: isArrayWithEachItem(isError),
  settings: isPartialOf<{ theme: string; notifications: boolean }>({
    theme: isString,
    notifications: isBoolean,
  }),
});

Installation

npm install guardz-generator

Usage

CLI

  • Generate all type guards using a config file:
    npx guardz-generator
    # or specify a config file
    npx guardz-generator --config guardz.config.ts
  • Generate for specific files:
    npx guardz-generator generate "src/**/*.ts"
  • Generate for a specific type:
    npx guardz-generator generate "src/**/*.ts" -t UserDTO
  • Skip post-processing:
    npx guardz-generator generate "src/**/*.ts" --no-post-process

Programmatic API

import { GenerateTypeGuardsUseCase } from 'guardz-generator';

// Using the use case (recommended)
const useCase = new GenerateTypeGuardsUseCase();
const files = await useCase.execute(['src/**/*.ts']);

// Generate a specific type guard
const typeGuardCode = await useCase.executeForSpecificType(['src/**/*.ts'], 'UserDTO');

// Legacy API (still supported)
import { TypeGuardGenerator } from 'guardz-generator';

const generator = new TypeGuardGenerator(['src/**/*.ts']);
const files = generator.generateAllTypeGuards();
await generator.writeTypeGuardsToSameDirectory(files);

// Generate a specific type guard
const typeGuardCode = generator.generateTypeGuard('UserDTO');

Supported TypeScript Features

Basic Types

  • Interfaces & Type Aliases: Generates guards for all your interfaces and type aliases.
  • Primitive Types: string, number, boolean, bigint, symbol
  • Nullable & Optional Types: Correctly handles null, undefined, and optional properties.
  • Arrays & Tuples: Generates guards for array and tuple types.

Advanced Types

  • Generics: Handles generic types and nested generics with explicit type parameters.
  • Enums: Generates guards using isEnum().
  • Union & Intersection Types: Full support for unions, intersections, and composite types.
  • Recursive Types: Handles direct and indirect recursion, including multi-way cycles.
  • BigInt & Advanced Number Types: Supports bigint and advanced number types like PositiveInteger, NonNegativeInteger, etc.
  • Interface Extensions: Correctly handles interface inheritance with proper type guards, using isExtensionOf and Omit to avoid duplicating inherited property checks.

Cross-File & External Types

  • Cross-file & NPM Imports: Resolves types across files and npm packages, using local guards or isAsserted as needed.
  • Smart Import Paths: Maintains your original import structure and path aliases.

Comprehensive Examples

1. Basic Interface

export interface User {
  id: number;
  name: string;
  email?: string;
  isActive: boolean;
}

Generated:

import type { User } from './_User';
import type { TypeGuardFn } from 'guardz';
import { isNumber, isString, isUndefinedOr, isBoolean, isType } from 'guardz';

export const isUser: TypeGuardFn<User> = isType<User>({
  id: isNumber,
  name: isString,
  email: isUndefinedOr(isString),
  isActive: isBoolean,
});

2. Interface Extensions

export interface Person {
  name: string;
  age: number;
}

export interface Employee extends Person {
  employeeId: string;
  department: string;
}

export interface Manager extends Employee {
  managedTeamSize: number;
}

Generated:

// isPerson.guardz.ts
export const isPerson: TypeGuardFn<Person> = isType<Person>({
  name: isString,
  age: isNumber,
});

// isEmployee.guardz.ts
export const isEmployee: TypeGuardFn<Employee> = isExtensionOf(
  isPerson,
  isType<Omit<Employee, keyof Person>>({
    employeeId: isString,
    department: isString,
  }),
);

// isManager.guardz.ts
export const isManager: TypeGuardFn<Manager> = isExtensionOf(
  isEmployee,
  isType<Omit<Manager, keyof Employee>>({
    managedTeamSize: isNumber,
  }),
);

Key Features:

  • Uses isExtensionOf to compose type guards
  • Uses Omit<Interface, keyof Base> to only check additional properties
  • Avoids duplicating inherited property validations
  • Supports multi-level inheritance chains

3. Generic Interfaces

export interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

export interface PaginatedResponse<T> extends ApiResponse<T[]> {
  totalPages: number;
  currentPage: number;
}

Generated:

// isApiResponse.guardz.ts
export const isApiResponse = <T>(
  typeGuardT: TypeGuardFn<T>,
): TypeGuardFn<ApiResponse<T>> =>
  isType<ApiResponse<T>>({
    data: typeGuardT,
    status: isNumber,
    message: isString,
  });

// isPaginatedResponse.guardz.ts
export const isPaginatedResponse = <T>(
  typeGuardT: TypeGuardFn<T>,
): TypeGuardFn<PaginatedResponse<T>> =>
  isExtensionOf(
    isApiResponse(isArrayWithEachItem(typeGuardT)),
    isType<Omit<PaginatedResponse<T>, keyof ApiResponse<T[]>>>({
      totalPages: isNumber,
      currentPage: isNumber,
    }),
  );

4. Union Types

export type UserStatus = 'active' | 'inactive' | 'pending';
export type UserRole = 'admin' | 'user' | 'moderator';

export interface User {
  id: number;
  status: UserStatus;
  role: UserRole;
  permissions: (UserRole | 'super_admin')[];
}

Generated:

export const isUserStatus = isOneOf('active', 'inactive', 'pending');
export const isUserRole = isOneOf('admin', 'user', 'moderator');

export const isUser: TypeGuardFn<User> = isType<User>({
  id: isNumber,
  status: isUserStatus,
  role: isUserRole,
  permissions: isArrayWithEachItem(
    isOneOf('admin', 'user', 'moderator', 'super_admin'),
  ),
});

5. Intersection Types

export interface HasId {
  id: number;
}

export interface HasTimestamps {
  createdAt: Date;
  updatedAt: Date;
}

export type Entity = HasId & HasTimestamps;

Generated:

export const isHasId: TypeGuardFn<HasId> = isType<HasId>({
  id: isNumber,
});

export const isHasTimestamps: TypeGuardFn<HasTimestamps> =
  isType<HasTimestamps>({
    createdAt: isDate,
    updatedAt: isDate,
  });

export const isEntity: TypeGuardFn<Entity> = isIntersectionOf(
  isHasId,
  isHasTimestamps,
);

6. Recursive Types

export interface TreeNode {
  value: number;
  children: TreeNode[];
}

export interface Comment {
  id: string;
  content: string;
  replies: Comment[];
}

Generated:

// isTreeNode.guardz.ts
export function isTreeNode(value: unknown): value is TreeNode {
  return isType<TreeNode>({
    value: isNumber,
    children: isArrayWithEachItem(isTreeNode),
  })(value);
}

// isComment.guardz.ts
export function isComment(value: unknown): value is Comment {
  return isType<Comment>({
    id: isString,
    content: isString,
    replies: isArrayWithEachItem(isComment),
  })(value);
}

7. Complex Types with Imports

import { AxiosResponse } from 'axios';
import { UserStatus } from '@/global/_GlobalTypesToImport';

export interface ApiUser {
  id: number;
  name: string | null;
  status: UserStatus;
  response: AxiosResponse;
  metadata: {
    lastLogin: Date;
    preferences: Record<string, unknown>;
  };
}

Generated:

import type { AxiosResponse } from 'axios';
import { isUserStatus } from '@/global/isUserStatus.guardz';
import type { ApiUser } from './_ApiUser';
import type { TypeGuardFn } from 'guardz';
import {
  isNumber,
  isNullOr,
  isString,
  isType,
  isDate,
  isObjectWithEachItem,
  isUnknown,
} from 'guardz';

export const isApiUser: TypeGuardFn<ApiUser> = isType<ApiUser>({
  id: isNumber,
  name: isNullOr(isString),
  status: isUserStatus,
  response: isAsserted<AxiosResponse>,
  metadata: isType<{
    lastLogin: Date;
    preferences: Record<string, unknown>;
  }>({
    lastLogin: isDate,
    preferences: isObjectWithEachItem(isUnknown),
  }),
});

8. Enum Types

export enum UserRole {
  ADMIN = 'admin',
  USER = 'user',
  MODERATOR = 'moderator',
}

export enum OrderStatus {
  PENDING = 'pending',
  CONFIRMED = 'confirmed',
  SHIPPED = 'shipped',
  DELIVERED = 'delivered',
  CANCELLED = 'cancelled',
}

Generated:

export const isUserRole = isEnum(UserRole);
export const isOrderStatus = isEnum(OrderStatus);

9. Advanced Number Types

export interface AdvancedNumbers {
  positive: PositiveInteger;
  nonNegative: NonNegativeInteger;
  percentage: number; // 0-100
  bigInt: bigint;
}

Generated:

export const isAdvancedNumbers: TypeGuardFn<AdvancedNumbers> =
  isType<AdvancedNumbers>({
    positive: isPositiveInteger,
    nonNegative: isNonNegativeInteger,
    percentage: isNumber,
    bigInt: isBigInt,
  });

10. Tuple Types

export type Coordinates = [number, number];
export type RGB = [number, number, number];
export type UserTuple = [string, number, boolean];

Generated:

export const isCoordinates = isTuple(isNumber, isNumber);
export const isRGB = isTuple(isNumber, isNumber, isNumber);
export const isUserTuple = isTuple(isString, isNumber, isBoolean);

11. Index Signatures

export interface StringMap {
  [key: string]: string;
}

export interface NumberMap {
  [key: string]: number;
}

export interface MixedMap {
  [key: string]: string | number;
}

Generated:

export const isStringMap = isObjectWithEachItem(isString);
export const isNumberMap = isObjectWithEachItem(isNumber);
export const isMixedMap = isObjectWithEachItem(isOneOf(isString, isNumber));

12. Conditional Types

export type NonNullable<T> = T extends null | undefined ? never : T;
export type ArrayElement<T> = T extends Array<infer U> ? U : never;
export type PromiseType<T> = T extends Promise<infer U> ? U : never;

Generated:

// Note: Conditional types are handled as their resolved types
// The generator will use the actual resolved type when possible
export const isNonNullable = <T>(
  typeGuardT: TypeGuardFn<T>,
): TypeGuardFn<NonNullable<T>> => isOneOf(typeGuardT, isNull, isUndefined);

13. Mapped Types

export type Partial<T> = { [P in keyof T]?: T[P] };
export type Required<T> = { [P in keyof T]-?: T[P] };
export type Readonly<T> = { readonly [P in keyof T]: T[P] };

Generated:

// Note: Mapped types are handled as their resolved types
// The generator will use the actual resolved interface structure
export const isPartial = <T>(
  typeGuardT: TypeGuardFn<T>,
): TypeGuardFn<Partial<T>> => typeGuardT; // Simplified - actual implementation depends on T

14. Template Literal Types

export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
export type ApiEndpoint = `/api/${string}`;
export type UserId = `user_${string}`;

Generated:

export const isHttpMethod = isOneOf('GET', 'POST', 'PUT', 'DELETE');
export const isApiEndpoint = isString; // Template literals are validated as strings
export const isUserId = isString; // Template literals are validated as strings

15. Utility Types

export type Pick<T, K extends keyof T> = { [P in K]: T[P] };
export type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
export type Record<K extends keyof any, T> = { [P in K]: T };

Generated:

// Note: Utility types are handled as their resolved types
// The generator will use the actual resolved interface structure
export const isPick = <T, K extends keyof T>(
  typeGuardT: TypeGuardFn<T>,
  keys: K[],
): TypeGuardFn<Pick<T, K>> => typeGuardT; // Simplified

export const isOmit = <T, K extends keyof any>(
  typeGuardT: TypeGuardFn<T>,
  keys: K[],
): TypeGuardFn<Omit<T, K>> => typeGuardT; // Simplified

export const isRecord = <K extends keyof any, T>(
  keyGuard: TypeGuardFn<K>,
  valueGuard: TypeGuardFn<T>,
): TypeGuardFn<Record<K, T>> => isObjectWithEachItem(valueGuard);

16. Function Types

export type EventHandler = (event: Event) => void;
export type AsyncFunction<T> = () => Promise<T>;
export type Callback<T> = (data: T) => void;

Generated:

export const isEventHandler = isFunction;
export const isAsyncFunction = <T>(
  typeGuardT: TypeGuardFn<T>,
): TypeGuardFn<AsyncFunction<T>> => isFunction; // Simplified - function types are validated as functions
export const isCallback = <T>(
  typeGuardT: TypeGuardFn<T>,
): TypeGuardFn<Callback<T>> => isFunction; // Simplified - function types are validated as functions

17. Class Types

export class User {
  constructor(
    public id: number,
    public name: string,
  ) {
  }
}

export interface UserInstance extends User {
  email: string;
}

Generated:

export const isUser = isInstanceOf(User);
export const isUserInstance = isExtensionOf(
  isUser,
  isType<Omit<UserInstance, keyof User>>({
    email: isString,
  }),
);

18. Branded Types

export type UserId = string & { readonly brand: unique symbol };
export type Email = string & { readonly brand: unique symbol };
export type Age = number & { readonly brand: unique symbol };

Generated:

export const isUserId = isString; // Branded types are validated as their base type
export const isEmail = isString; // Branded types are validated as their base type
export const isAge = isNumber; // Branded types are validated as their base type

19. Const Assertions

export const STATUS = ['active', 'inactive', 'pending'] as const;
export type Status = (typeof STATUS)[number];

export const CONFIG = {
  api: 'https://api.example.com',
  timeout: 5000,
} as const;
export type Config = typeof CONFIG;

Generated:

export const isStatus = isOneOf('active', 'inactive', 'pending');
export const isConfig = isType<Config>({
  api: isString,
  timeout: isNumber,
});

20. Complex Nested Types

export interface ComplexUser {
  id: number;
  profile: {
    name: string;
    avatar?: string;
    preferences: {
      theme: 'light' | 'dark';
      notifications: boolean;
    };
  };
  posts: Array<{
    id: string;
    title: string;
    content: string;
    tags: string[];
    published: boolean;
  }>;
  metadata: Record<string, unknown>;
}

Generated:

export const isComplexUser: TypeGuardFn<ComplexUser> = isType<ComplexUser>({
  id: isNumber,
  profile: isType<{
    name: string;
    avatar?: string;
    preferences: {
      theme: 'light' | 'dark';
      notifications: boolean;
    };
  }>({
    name: isString,
    avatar: isUndefinedOr(isString),
    preferences: isType<{
      theme: 'light' | 'dark';
      notifications: boolean;
    }>({
      theme: isOneOf('light', 'dark'),
      notifications: isBoolean,
    }),
  }),
  posts: isArrayWithEachItem(
    isType<{
      id: string;
      title: string;
      content: string;
      tags: string[];
      published: boolean;
    }>({
      id: isString,
      title: isString,
      content: isString,
      tags: isArrayWithEachItem(isString),
      published: isBoolean,
    }),
  ),
  metadata: isObjectWithEachItem(isUnknown),
});

Advanced Capabilities

  • Automatic Post-Processing: Optionally runs Prettier, ESLint, and TypeScript checks on generated files.
  • Cycle Detection: Detects and handles recursive and cyclic type references.
  • Custom Type Guards: Generate custom guards for any TypeScript type node.
  • AST Utilities: Exposes utilities for advanced users (e.g., property extraction, recursion detection).
  • Import Path Consistency: Maintains your project's import structure and path aliases.
  • External Package Support: Properly handles types from npm packages with smart fallback logic.

Complete Feature Support

Guardz Generator supports all major TypeScript features:

✅ Basic Types

  • Primitive Types: string, number, boolean, bigint, symbol
  • Nullable Types: string | null, number | undefined, etc.
  • Optional Properties: name?: string
  • Arrays: string[], number[], Array<T>
  • Tuples: [string, number], [number, number, number]

✅ Complex Types

  • Union Types: 'active' | 'inactive' | 'pending'
  • Intersection Types: HasId & HasTimestamps
  • Generic Types: ApiResponse<T>, PaginatedResponse<T>
  • Recursive Types: Self-referencing interfaces and types
  • Index Signatures: { [key: string]: unknown }

✅ Interface Features

  • Basic Interfaces: Simple property definitions
  • Interface Extensions: interface B extends A with proper inheritance
  • Multi-level Inheritance: A extends B extends C
  • Generic Interfaces: interface Container<T>
  • Interface Merging: Multiple interface declarations

✅ Type Aliases

  • Basic Type Aliases: type UserId = string
  • Union Type Aliases: type Status = 'active' | 'inactive'
  • Generic Type Aliases: type Result<T> = Success<T> | Error
  • Mapped Types: type Partial<T> = { [P in keyof T]?: T[P] }
  • Conditional Types: type NonNullable<T> = T extends null | undefined ? never : T
  • Template Literal Types: type UserId = user_${string}``
  • Branded Types: type UserId = string & { readonly brand: unique symbol }
  • Const Assertions: type Status = typeof STATUS[number]

✅ Advanced Features

  • Enums: Both string and numeric enums
  • BigInt Support: bigint type and operations
  • Advanced Number Types: PositiveInteger, NonNegativeInteger, etc.
  • Cross-file References: Types imported from other files
  • NPM Package Types: Types from external packages
  • Path Aliases: @/types/User@/types/User.guardz
  • Index Signatures: { [key: string]: string }
  • Function Types: (event: Event) => void
  • Class Types: class User with isInstanceOf
  • Utility Types: Pick, Omit, Record, etc.
  • Complex Nested Types: Deep object structures with arrays and unions

✅ Import Handling

  • Relative Imports: './models/User''./models/User.guardz'
  • Path Aliases: '@/types/ApiResponse''@/types/ApiResponse.guardz'
  • Global Imports: '@/global/_GlobalTypes''@/global/isTypeName.guardz'
  • NPM Packages: 'axios'isAsserted<AxiosResponse>
  • Smart Fallbacks: Uses local guards when available, falls back to isAsserted

✅ Code Quality

  • Prettier Formatting: Consistent code style
  • ESLint Integration: Lint generated files
  • TypeScript Checking: Verify generated code compiles
  • Error Handling: Graceful handling of unsupported types
  • Performance: Efficient AST traversal and code generation

Configuration

Create a guardz.config.ts file in your project root:

export default {
  includes: ['src/**/*.ts'],
  excludes: ['node_modules/**/*', '**/*.test.ts', '**/*.guardz.ts'],
  output: './generated',
  postProcess: true,
};

Why Use Guardz Generator?

  • Save Time: No more hand-writing repetitive type guards.
  • Increase Safety: Get runtime validation for your TypeScript types.
  • Stay Up-to-date: Supports the latest TypeScript and guardz 1.9.0 features including new Web API guards.
  • Flexible: Use in any project, with CLI or API.
  • Consistent: Maintains your project's import structure and conventions.
  • Comprehensive: Handles all TypeScript features including generics, unions, intersections, and interface extensions.

Support This Project

If you find Guardz Generator helpful, please consider supporting its development! Your sponsorship helps maintain and improve this open-source project.

GitHub Sponsors

GitHub Sponsors

Sponsorship Tiers

  • $5/month - Supporter 🎉

    • Get your name listed as a supporter
    • Early access to new features
    • Priority issue responses
  • $20/month - Coffee + Shout-out

    • All Supporter benefits
    • Monthly shout-out on social media
    • Direct access to development roadmap
  • $100/month - Company Sponsor 🏢

    • All previous benefits
    • Company logo featured in README
    • Dedicated support channel
    • Custom feature requests
  • $500+/month - Integration/Consulting Call 💼

    • All previous benefits
    • Monthly 1-hour consulting call
    • Custom integration support
    • White-label solutions
    • Enterprise deployment assistance

Other Ways to Support

  • Star the repository if you find it useful
  • 🐛 Report bugs and suggest improvements
  • 📝 Contribute code via pull requests
  • 📢 Share with your network

License

MIT