Skip to content

Feature: Smart Type Inference Improvements #67

@Goldziher

Description

@Goldziher

Feature: Smart Type Inference Improvements

Enhance TypeScript type inference capabilities to provide better developer experience, more accurate types, and improved error messages.

Problem Statement

Current type inference limitations:

  • Complex nested factory types can lose precision
  • Error messages for type mismatches can be cryptic
  • Conditional types in schemas aren't always properly inferred
  • Factory composition can result in any types
  • Runtime type validation doesn't align with compile-time types

Proposed Features

1. Enhanced Type Inference for Nested Factories

// Current: Types may be lost in deep nesting
const factory = new Factory({
  user: {
    profile: {
      settings: {
        preferences: { theme: 'dark' }
      }
    }
  }
});

// Improved: Full type preservation
type InferredType = FactoryType<typeof factory>;
// Correctly infers: { user: { profile: { settings: { preferences: { theme: string } } } } }

2. Better Error Messages

// Current: Generic error
// Type 'string' is not assignable to type 'never'

// Improved: Contextual error
// Factory field 'user.email' expects type 'string' but received 'number'
// Hint: Did you mean to use faker.internet.email() instead of faker.number.int()?

3. Conditional Type Support

type User<T extends 'admin' | 'user'> = {
  id: string;
  role: T;
  permissions: T extends 'admin' ? string[] : never;
};

// Factory should correctly infer based on discriminated unions
const AdminFactory = new Factory<User<'admin'>>((faker) => ({
  id: faker.string.uuid(),
  role: 'admin' as const,
  permissions: ['read', 'write', 'delete'] // Type-safe\!
}));

4. Improved Composition Types

// Better type inference for composed factories
const BaseFactory = new Factory<Base>({ id: faker => faker.string.uuid() });
const ExtendedFactory = BaseFactory.extend<Extended>({ 
  name: faker => faker.person.fullName() 
});

// Should infer: Factory<Base & { name: string }>
// Not: Factory<any>

5. Runtime Type Validation

// Align runtime checks with compile-time types
const factory = new Factory<User>(schema, {
  typeValidation: {
    enabled: true,
    mode: 'development', // Only in dev
    onMismatch: (field, expected, actual) => {
      console.error(`Type mismatch in ${field}: expected ${expected}, got ${actual}`);
    }
  }
});

// Runtime validation matches TypeScript types
const user = factory.build(); // Validates at runtime

Implementation Features

Type-Safe Factory References

// Type-safe references between factories
const PostFactory = new Factory<Post>((faker, refs) => ({
  id: faker.string.uuid(),
  authorId: refs.User.id, // Typed reference to UserFactory
  author: refs.User.build() // Full type inference
}));

Generic Factory Support

// Better generics handling
function createFactory<T extends Record<string, any>>(
  schema: FactorySchema<T>
): Factory<T> {
  return new Factory<T>(schema);
}

// Maintains full type inference
const factory = createFactory({
  id: (faker) => faker.string.uuid(),
  name: (faker) => faker.person.fullName()
}); // Correctly infers all field types

Template Literal Types

// Support for template literal types
type EventType = `user.${string}`;

const EventFactory = new Factory<{ type: EventType }>((faker) => ({
  type: faker.helpers.arrayElement([
    'user.created',
    'user.updated',
    'user.deleted'
  ] as const)
}));

Developer Experience Improvements

1. IntelliSense Enhancements

// Rich IntelliSense with examples
factory.build({
  email: // IntelliSense shows:
         // Expected: string (email format)
         // Example: "john.doe@example.com"
         // Faker: faker.internet.email()
});

2. Type Hovering

// Hover to see resolved types
const factory = new Factory(complexSchema);
// Hover shows: Factory<{ id: string, user: { name: string, age: number }, ... }>

3. Auto-completion

// Smart auto-completion based on schema
factory.build({
  us‸ // Autocompletes to 'user'
});

Type Utilities

// Export useful type utilities
import { FactoryType, FactorySchema, InferFactory } from 'interface-forge';

// Extract generated type from factory
type User = FactoryType<typeof UserFactory>;

// Create schema with type checking
const schema: FactorySchema<User> = {
  id: (faker) => faker.string.uuid(),
  email: (faker) => faker.internet.email()
};

// Infer factory from schema
type InferredFactory = InferFactory<typeof schema>;

Testing Requirements

  • Type-level tests using tsd or similar
  • Compile-time performance benchmarks
  • IntelliSense behavior testing
  • Error message clarity validation
  • Generic type preservation tests
  • Conditional type tests

Example: Complex Type Inference

// Complex nested structure with full type inference
type Organization = {
  id: string;
  type: 'company' | 'nonprofit';
  details: {
    name: string;
    founded: Date;
    employees: Array<{
      id: string;
      role: 'admin' | 'member';
      permissions: string[];
    }>;
  };
};

const OrgFactory = new Factory<Organization>((faker) => ({
  id: faker.string.uuid(),
  type: faker.helpers.arrayElement(['company', 'nonprofit'] as const),
  details: {
    name: faker.company.name(),
    founded: faker.date.past(),
    employees: faker.repeat(() => ({
      id: faker.string.uuid(),
      role: faker.helpers.arrayElement(['admin', 'member'] as const),
      permissions: faker.helpers.arrayElements(['read', 'write', 'delete'])
    }), { min: 1, max: 10 })
  }
}));

// All types are correctly inferred, including:
// - Literal types for 'company' | 'nonprofit'
// - Nested object types
// - Array types with proper element types

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions