JSPM

  • Created
  • Published
  • Downloads 28
  • Score
    100M100P100Q60735F
  • License MIT

Advanced TypeScript type guard generator with sophisticated recursion detection and enhanced enum handling using guardz 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

A TypeScript type guard generator that uses the guardz library (v1.0.6) to generate runtime type checking functions from TypeScript interfaces and type aliases.

Features

  • Functional Architecture: Built with functional programming principles for better maintainability and testability
  • Modular Design: Separated concerns into focused modules (AST utils, type detection, generators, etc.)
  • Type Safety: Full TypeScript support with proper type definitions
  • Generic Support: Handles generic interfaces and type aliases
  • Advanced Recursion Support: Detects both direct and indirect recursive types with sophisticated cycle detection
  • Enhanced Enum Handling: Uses isEnum(EnumName) format for cleaner enum type guards
  • Union Types: Generates guards for union types including null/undefined handling
  • Cross-file References: Resolves types across multiple files
  • Prettier Integration: Automatically formats generated code

Installation

npm install guardz-generator

Usage

CLI

Generate type guards for all exported interfaces and type aliases:

npx guardz-generator generate "src/**/*.ts"

Generate a type guard for a specific type:

npx guardz-generator generate "src/**/*.ts" -t UserDTO

Programmatic API

import { TypeGuardGenerator } from 'guardz-generator';

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

// Generate all type guards
const files = generator.generateAllTypeGuards();
await generator.writeTypeGuardsToSameDirectory(files);

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

Architecture

The project follows functional programming principles with clear separation of concerns:

Core Modules

  • src/types.ts: Type definitions and interfaces
  • src/core/type-guard-generator.ts: Main orchestrator class
  • src/generators/: Type guard generation logic
    • type-guard-generators.ts: Handles different TypeScript node types
    • interface-generators.ts: Interface-specific generation
    • type-alias-generators.ts: Type alias generation
    • file-generators.ts: File generation utilities
  • src/utils/: Pure utility functions
    • ast-utils.ts: AST manipulation utilities including cycle detection
    • type-detection.ts: Type detection and validation
    • import-collectors.ts: Import statement generation

Functional Principles

  1. Pure Functions: Most functions are pure and side-effect free
  2. Composition: Complex operations are built from smaller, focused functions
  3. Immutability: Data structures are treated as immutable
  4. Separation of Concerns: Each module has a single responsibility
  5. Testability: Functions are easily testable in isolation

Supported TypeScript Features

New in v1.0.6 - Latest guardz Features

The generator now supports all the latest guardz 1.0.6 features:

Advanced Number Types

export interface User {
  id: PositiveInteger;        // > 0 and whole number
  age: NonNegativeInteger;    // ≥ 0 and whole number
  score: Integer;             // whole number
  temperature: NegativeNumber; // < 0
}

// Generates:
export const isUser = isType<User>({
  id: isPositiveInteger,
  age: isNonNegativeInteger,
  score: isInteger,
  temperature: isNegativeNumber,
});

BigInt Support

export interface LargeData {
  bigId: bigint;
  timestamp: bigint;
}

// Generates:
export const isLargeData = isType<LargeData>({
  bigId: isBigInt,
  timestamp: isBigInt,
});

Enhanced Nullable/Optional Types

export interface Config {
  name: string | null | undefined;  // Uses isNilOr
  email?: string | null;            // Uses isUndefinedOr
}

// Generates:
export const isConfig = isType<Config>({
  name: isNilOr(isString),
  email: isUndefinedOr(isNullOr(isString)),
});

Tuple Types

export interface Coordinates {
  point: [number, number];
  data: [string, number, boolean];
}

// Generates:
export const isCoordinates = isType<Coordinates>({
  point: isTuple([isNumber, isNumber]),
  data: isTuple([isString, isNumber, isBoolean]),
});

Composite Types

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

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

// Generates:
export const isPerson = isType<Person>({ name: isString, age: isNumber });
export const isEmployee = isExtensionOf(isPerson, isType<Employee>({
  employeeId: isString,
  department: isString,
}));

Interfaces

export interface User {
  id: number;
  name: string;
  email?: string;
  profile: UserProfile;
}

// Generates:
export const isUser = isType<User>({
  id: isNumber,
  name: isString,
  email: isUndefinedOr(isString),
  profile: isUserProfile,
});

Generic Interfaces

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

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

Enums

export enum UserStatus {
  ACTIVE = 'active',
  INACTIVE = 'inactive',
  PENDING = 'pending',
}

export interface User {
  id: number;
  status: UserStatus;
}

// Generates:
import { UserStatus } from './types';
export const isUser = isType<User>({
  id: isNumber,
  status: isEnum(UserStatus),
});

Type Aliases

export type UserRole = 'admin' | 'user' | 'guest';

// Generates:
export const isUserRole = isOneOf('admin', 'user', 'guest');

Union Types

export interface User {
  id: number;
  name: string | null;
  role: 'admin' | 'user' | 'guest';
}

// Generates:
export const isUser = isType<User>({
  id: isNumber,
  name: isNullOr(isString),
  role: isOneOf('admin', 'user', 'guest'),
});

Direct Recursive Types

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

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

Indirect Recursive Types

// Type A references Type B, Type B references Type A
export interface NodeA {
  id: number;
  nodeB: NodeB;
}

export interface NodeB {
  id: number;
  nodeA: NodeA;
}

// Generates function format for both types:
export function isNodeA(value: unknown): value is NodeA {
  return isType<NodeA>({
    id: isNumber,
    nodeB: isNodeB,
  })(value);
}

export function isNodeB(value: unknown): value is NodeB {
  return isType<NodeB>({
    id: isNumber,
    nodeA: isNodeA,
  })(value);
}

Advanced Features

Sophisticated Cycle Detection

The generator uses a dependency graph with depth-first search to detect complex recursive patterns:

  • Direct recursion: TreeNode contains TreeNode[]
  • Indirect recursion: NodeANodeBNodeA
  • Multi-way cycles: AlphaBetaGammaAlpha

All recursive types automatically use function format to handle circular references properly.

Enhanced Enum Support

Enums are detected automatically and use the isEnum() function:

// Instead of generating separate isUserStatus.guardz.ts file:
export const isUserStatus = isEnum(UserStatus);

// Direct enum import and usage:
import { UserStatus } from './types';
status: isEnum(UserStatus)

Advanced Usage

Custom Type Guards

import { convertTypeToGuard } from 'guardz-generator';

const typeNode = // ... TypeScript AST node
const guardCode = convertTypeToGuard(typeNode, { sourceFiles });

AST Utilities

import { 
  extractProperties, 
  isRecursiveType, 
  isRecursiveOrCyclic,
  buildTypeDependendencyGraph,
  detectCycles 
} from 'guardz-generator';

// Check for direct recursion
const isRecursive = isRecursiveType(interfaceDecl);

// Check for both direct and indirect recursion
const isCyclic = isRecursiveOrCyclic(interfaceDecl, allInterfaces);

// Build dependency graph for analysis
const graph = buildTypeDependendencyGraph(interfaces);
const cyclicTypes = detectCycles(graph);

Type Detection

import { isEnumType, isInterfaceType } from 'guardz-generator';

const isEnum = isEnumType('UserRole', sourceFiles);
const isInterface = isInterfaceType('User', sourceFiles);

Configuration

The generator uses TypeScript compiler options optimized for type guard generation:

{
  target: ts.ScriptTarget.ES2020,
  module: ts.ModuleKind.CommonJS,
  strict: true,
  esModuleInterop: true,
  skipLibCheck: true,
}

Contributing

The project follows functional programming principles:

  1. Pure Functions: Keep functions pure and side-effect free
  2. Small Functions: Break complex operations into smaller, focused functions
  3. Type Safety: Use TypeScript types extensively
  4. Composition: Build complex operations from simpler ones
  5. Testing: Write tests for individual functions

License

MIT