Agent Skill
2/7/2026

type-system-governance

Enforce TypeScript type organization rules. Use when creating types, interfaces, or DTOs. All types MUST go in /types directory - never inline in components.

E
esdeveniments
2GitHub Stars
1Views
npx skills add Esdeveniments/esdeveniments-frontend

SKILL.md

Nametype-system-governance
DescriptionEnforce TypeScript type organization rules. Use when creating types, interfaces, or DTOs. All types MUST go in /types directory - never inline in components.

name: type-system-governance description: Enforce TypeScript type organization rules. Use when creating types, interfaces, or DTOs. All types MUST go in /types directory - never inline in components.

Type System Governance

āš ļø ALL types and interfaces MUST be defined in the /types directory.

This skill enforces strict type organization to prevent duplication, maintain DRY principle, and ensure consistent type imports across the codebase.


🚨 THE GOLDEN RULE

// āŒ FORBIDDEN: Type defined outside /types
// File: components/ui/Button.tsx
type ButtonProps = { variant: string }; // WRONG!

// āœ… REQUIRED: Type defined in /types
// File: types/props.ts
export interface ButtonProps {
  variant: ButtonVariant;
}

// File: components/ui/Button.tsx
import type { ButtonProps } from "types/props";

ESLint enforces this rule - you will get lint errors for inline types.


šŸ“ Type Organization Structure

types/
ā”œā”€ā”€ README.md              # Type organization guide (READ THIS FIRST)
ā”œā”€ā”€ common.ts              # Shared UI types
│   ā”œā”€ā”€ NavigationItem
│   ā”œā”€ā”€ SocialLinks
│   └── ...
ā”œā”€ā”€ props.ts               # Component props types
│   ā”œā”€ā”€ ButtonProps
│   ā”œā”€ā”€ CardProps
│   └── ...
ā”œā”€ā”€ event.ts               # Event domain types
│   ā”œā”€ā”€ EventFilters
│   ā”œā”€ā”€ EventCardData
│   └── distanceToRadius()
ā”œā”€ā”€ filters.ts             # Filter system types
│   ā”œā”€ā”€ FilterConfig
│   ā”œā”€ā”€ FilterState
│   └── ...
ā”œā”€ā”€ i18n.ts                # i18n types
│   ā”œā”€ā”€ Locale
│   ā”œā”€ā”€ SupportedLocale
│   └── ...
ā”œā”€ā”€ api/                   # API DTOs
│   ā”œā”€ā”€ event.ts           # EventDTO, EventResponseDTO
│   ā”œā”€ā”€ news.ts            # NewsDTO, NewsResponseDTO
│   ā”œā”€ā”€ city.ts            # CitySummaryResponseDTO
│   ā”œā”€ā”€ region.ts          # RegionDTO
│   └── category.ts        # CategoryDTO
└── index.ts               # Re-exports (optional)

āœ… Step-by-Step: Adding a New Type

1. Determine the Canonical Location

Type CategoryLocationExample
API response DTOtypes/api/<domain>.tsEventResponseDTO
Component propstypes/props.tsButtonProps
Shared UI typestypes/common.tsNavigationItem
Domain-specifictypes/<domain>.tsFilterConfig
Utility typesNear usage in types/DateRange

2. Check for Existing Types

# Search for existing types
grep -r "interface\|type " types/ --include="*.ts"

# Search for specific type name
grep -r "ButtonProps\|CardProps" types/

# Check canonical sources
cat types/common.ts | grep "export"
cat types/props.ts | grep "export"

3. Add Type to Correct File

// types/props.ts
export interface NewComponentProps {
  variant: "primary" | "secondary";
  size?: "sm" | "md" | "lg";
  children: React.ReactNode;
}

4. Import and Use

// components/ui/NewComponent.tsx
import type { NewComponentProps } from "types/props";

export function NewComponent({
  variant,
  size = "md",
  children,
}: NewComponentProps) {
  // ...
}

🚫 Common Violations (And How to Fix)

āŒ Violation 1: Inline Type Definition

// WRONG: Type in component file
// components/ui/Card.tsx
type CardProps = {
  title: string;
  description: string;
};

export function Card({ title, description }: CardProps) {
  /* ... */
}

Fix:

// types/props.ts
export interface CardProps {
  title: string;
  description: string;
}

// components/ui/Card.tsx
import type { CardProps } from "types/props";

export function Card({ title, description }: CardProps) {
  /* ... */
}

āŒ Violation 2: Duplicate Type Definition

// WRONG: Same type defined in multiple places
// components/ui/EventCard.tsx
interface Event {
  id: number;
  title: string;
}

// components/ui/EventList.tsx
interface Event {
  id: number;
  title: string;
} // Duplicate!

Fix:

// types/event.ts
export interface Event {
  id: number;
  title: string;
}

// Both components import from same source
import type { Event } from "types/event";

āŒ Violation 3: API DTO Not in /types/api

// WRONG: DTO defined in lib/api
// lib/api/events.ts
interface EventResponse {
  content: Event[];
  totalPages: number;
}

Fix:

// types/api/event.ts
export interface EventResponseDTO {
  content: EventDTO[];
  totalPages: number;
  totalElements: number;
  last: boolean;
}

// lib/api/events.ts
import type { EventResponseDTO } from "types/api/event";

āŒ Violation 4: Using any

// WRONG: Using any
const handleData = (data: any) => {
  /* ... */
};

Fix:

// Use unknown with proper narrowing
const handleData = (data: unknown) => {
  if (isEventData(data)) {
    // data is now typed as EventData
  }
};

// Or define proper type
import type { EventData } from "types/event";
const handleData = (data: EventData) => {
  /* ... */
};

šŸ“‹ Type Consolidation Workflow

When you find duplicate types:

Step 1: Identify Duplicates

# Find all type definitions
grep -r "interface\|type " --include="*.ts" --include="*.tsx" | grep -v "types/"

# Check for specific duplicates
grep -rn "interface Event\|type Event" --include="*.ts"

Step 2: Choose Canonical Location

  • Is it a DTO? → types/api/<domain>.ts
  • Is it UI props? → types/props.ts
  • Is it shared? → types/common.ts
  • Is it domain-specific? → types/<domain>.ts

Step 3: Consolidate

// Move to canonical location
// types/common.ts
export interface ConsolidatedType {
  // ...
}

Step 4: Update All Imports

# Find all usages
grep -rn "ConsolidatedType" --include="*.ts" --include="*.tsx"

# Update imports in each file
import type { ConsolidatedType } from 'types/common';

Step 5: Verify

yarn typecheck && yarn lint

šŸ”§ Quick Reference: Canonical Sources

TypeCanonical FileImport Path
NavigationItemtypes/common.tstypes/common
SocialLinkstypes/common.tstypes/common
ButtonPropstypes/props.tstypes/props
EventDTOtypes/api/event.tstypes/api/event
FilterConfigtypes/filters.tstypes/filters
CitySummaryResponseDTOtypes/api/city.tstypes/api/city
Localetypes/i18n.tstypes/i18n

āœ… Verification Checklist

Before submitting code with types:

  • All types defined in /types directory
  • No inline type or interface in components
  • Checked types/README.md for existing patterns
  • No duplicate type definitions
  • Using unknown instead of any where needed
  • Props types in types/props.ts
  • API DTOs in types/api/*.ts
  • yarn typecheck passes
  • yarn lint passes (ESLint catches inline types)

šŸ” ESLint Rule Enforcement

This project has ESLint rules that block type definitions outside /types:

// eslint.config.mjs
{
  rules: {
    'no-restricted-syntax': [
      'error',
      {
        selector: 'TSTypeAliasDeclaration',
        message: 'Type aliases must be defined in /types directory'
      },
      {
        selector: 'TSInterfaceDeclaration',
        message: 'Interfaces must be defined in /types directory'
      }
    ]
  }
}

If you see this error, move your type to the appropriate file in /types.


šŸ’” Pro Tips

Use Path Aliases

// āœ… Good: Use path alias
import type { Event } from "types/event";

// āŒ Avoid: Relative paths
import type { Event } from "../../../types/event";

Export Types Properly

// types/event.ts
export interface Event {
  /* ... */
}
export type EventStatus = "draft" | "published";

// Re-export if needed
// types/index.ts
export type { Event, EventStatus } from "./event";

Type vs Interface

// Use interface for objects (extendable)
export interface Event {
  id: number;
  title: string;
}

// Use type for unions, primitives, computed types
export type EventStatus = "draft" | "published" | "archived";
export type EventId = Event["id"];

Remember: Types in /types directory = maintainable codebase.

Last Updated: January 15, 2026

Skills Info
Original Name:type-system-governanceAuthor:esdeveniments