Install any skill in seconds. Free to start, no credit card required.
Get Started Free →All TypeScript types are defined in `frontend/types/index.ts`. Types match backend API response structure and provide type safety across the frontend application.
.claude/skills/aiskillstore-frontend-types/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-09 | ✗→✓ | ▲ Improved | 449% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 101% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 114% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 98% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 239% | 0% |
Purpose: Guidance for creating TypeScript type definitions following existing patterns from frontend/types/index.ts.
All TypeScript types are defined in frontend/types/index.ts. Types match backend API response structure and provide type safety across the frontend application.
frontend/types/index.tstypescriptexport interface User { id: string; email: string; name: string; createdAt?: string; updatedAt?: string; } export interface UserCredentials { email: string; password: string; } export interface UserSignupData extends UserCredentials { name: string; }
Pattern:
interface for object types?extends for type inheritancetypescriptexport type TaskStatus = "pending" | "completed"; export type TaskPriority = "low" | "medium" | "high"; export interface Task { id: number; user_id: string; title: string; description?: string; completed: boolean; priority: TaskPriority; due_date?: string; tags: string[]; created_at: string; updated_at: string; } export interface TaskFormData { title: string; description?: string; priority?: TaskPriority; due_date?: string; tags?: string[]; } export interface TaskQueryParams { status?: "all" | "pending" | "completed"; sort?: "created" | "title" | "updated" | "priority" | "due_date"; search?: string; page?: number; limit?: number; }
Pattern:
type for union types (string literals)interface for object typesuser_id, due_date, created_at)typescriptexport interface ApiResponse<T = unknown> { data?: T; success: boolean; message?: string; error?: { code: string; message: string; details?: unknown; }; } export interface PaginatedResponse<T> { data: T[]; meta: { total: number; page: number; limit: number; totalPages: number; }; }
Pattern:
<T> for reusable structures<T = unknown>)success boolean flagdata, message, and error fieldsmeta objecttypescriptexport interface AuthResponse { success: boolean; token: string; user: User; } export interface Session { user: User; token: string; expiresAt: number; }
Pattern:
success booleantoken stringuser object (User type)expiresAt timestamp for sessiontypescriptexport interface AppError { message: string; code?: string; statusCode?: number; field?: string; } export interface FormErrors { [key: string]: string | undefined; }
Pattern:
interface for error objects?[key: string] for dynamic object types (FormErrors)typescriptexport type LoadingState = "idle" | "loading" | "success" | "error"; export type ToastType = "success" | "error" | "warning" | "info"; export interface ToastMessage { id: string; type: ToastType; message: string; duration?: number; }
Pattern:
type for union types (string literals)interface for object typesid for unique identification?typescriptexport type ExportFormat = "csv" | "json"; export interface ImportResult { imported: number; errors: number; errorDetails?: string[]; }
Pattern:
type for union types (string literals)interface for result objectsUser, Task, ApiResponseTaskFormData, UserSignupDataTaskStatus, TaskPriority, LoadingStateToastType, ExportFormatTaskItemProps, ProtectedRoutePropsinterface TaskItemProps { task: Task; }TaskFormData, UserSignupDatainterface TaskFormData { title: string; description?: string; }TaskQueryParamsinterface TaskQueryParams { status?: "all" | "pending" | "completed"; }Backend (snake_case) → Frontend (camelCase for form data, snake_case for API response)
typescript// Backend API response (matches backend exactly) export interface Task { id: number; user_id: string; // snake_case from backend title: string; due_date?: string; // snake_case from backend created_at: string; // snake_case from backend updated_at: string; // snake_case from backend } // Frontend form data (camelCase for easier use) export interface TaskFormData { title: string; dueDate?: string; // camelCase for frontend tags?: string[]; }
Pattern:
typescript// Backend API response (all fields from backend) export interface Task { id: number; // Required (from backend) user_id: string; // Required (from backend) title: string; // Required (from backend) description?: string; // Optional (from backend) completed: boolean; // Required (from backend) priority: TaskPriority; // Required (from backend) due_date?: string; // Optional (from backend) tags: string[]; // Required (from backend, can be empty array) created_at: string; // Required (from backend) updated_at: string; // Required (from backend) } // Frontend form data (only fields user can edit) export interface TaskFormData { title: string; // Required (user must provide) description?: string; // Optional priority?: TaskPriority; // Optional (has default) due_date?: string; // Optional tags?: string[]; // Optional (can be empty array) }
Pattern:
??interface for Objectstypescriptexport interface User { id: string; email: string; }
When to use: Object types with properties
type for Unions, Intersections, or Aliasestypescriptexport type TaskStatus = "pending" | "completed"; export type TaskPriority = "low" | "medium" | "high";
When to use: Union types, intersections, or type aliases
typescriptexport interface ApiResponse<T = unknown> { data?: T; success: boolean; }
When to use: Reusable structures that work with different types
?typescriptexport interface Task { title: string; // Required description?: string; // Optional }
When to use: Fields that may not exist
typescriptexport interface Category { id: number; user_id: string; name: string; color?: string; created_at: string; updated_at: string; }
typescriptexport interface CategoryFormData { name: string; color?: string; }
typescriptexport interface CategoryQueryParams { search?: string; page?: number; limit?: number; }
typescriptasync getCategories( userId: string, queryParams?: CategoryQueryParams ): Promise<ApiResponse<PaginatedResponse<Category>>> { // Implementation }
specs/002-frontend-todo-app/spec.md - Entity definitionsspecs/002-frontend-todo-app/plan.md - API contracts with typesfrontend/types/index.ts - Complete type definitionsinterface for object typestype for union types (string literals)<T> for reusable structures?<T = unknown>)| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-10 | pass→pass | 2,706 | 7,955 | +194% | 1 | 1 | 0% | 485 | 3,052 | +529% | 0 | 0 | — |
case-09 | fail→pass | 3,410 | 8,985 | +163% | 1 | 1 | 0% | 583 | 3,203 | +449% | 0 | 0 | — |
case-01 | fail→pass | 16,230 | 12,489 | -23% | 1 | 1 | 0% | 1,945 | 3,900 | +101% | 0 | 0 | — |
case-02 | fail→pass | 9,245 | 7,961 | -14% | 1 | 1 | 0% | 1,894 | 4,058 | +114% | 0 | 0 | — |
case-03 | fail→pass | 9,619 | 10,875 | +13% | 1 | 1 | 0% | 1,792 | 3,543 | +98% | 0 | 0 | — |
case-04 | pass→fail | 9,072 | 12,267 | +35% | 1 | 1 | 0% | 1,785 | 3,887 | +118% | 0 | 0 | — |
case-05 | fail→pass | 5,771 | 11,162 | +93% | 1 | 1 | 0% | 1,077 | 3,655 | +239% | 0 | 0 | — |
case-06 | pass→pass | 4,864 | 9,415 | +94% | 1 | 1 | 0% | 824 | 3,451 | +319% | 0 | 0 | — |
case-07 | fail→pass | 12,686 | 10,191 | -20% | 1 | 1 | 0% | 1,567 | 3,456 | +121% | 0 | 0 | — |
case-08 | pass→pass | 5,773 | 5,932 | +3% | 1 | 1 | 0% | 1,105 | 3,603 | +226% | 0 | 0 | — |
case-11 | fail→pass | 12,618 | 7,598 | -40% | 1 | 1 | 0% | 1,377 | 4,061 | +195% | 0 | 0 | — |
case-12 | fail→pass | 7,263 | 5,655 | -22% | 1 | 1 | 0% | 1,415 | 3,606 | +155% | 0 | 0 | — |
case-13 | pass→pass | 9,046 | 8,676 | -4% | 1 | 1 | 0% | 725 | 3,254 | +349% | 0 | 0 | — |
case-14 | fail→pass | 12,120 | 12,627 | +4% | 1 | 1 | 0% | 1,387 | 3,965 | +186% | 0 | 0 | — |
case-15 | pass→pass | 6,153 | 11,666 | +90% | 1 | 1 | 0% | 1,310 | 3,830 | +192% | 0 | 0 | — |
case-16 | fail→pass | 12,907 | 7,053 | -45% | 1 | 1 | 0% | 1,476 | 3,463 | +135% | 0 | 0 | — |
case-17 | pass→pass | 12,404 | 6,967 | -44% | 1 | 1 | 0% | 1,346 | 3,763 | +180% | 0 | 0 | — |
case-18 | pass→pass | 7,802 | 3,471 | -56% | 1 | 1 | 0% | 1,518 | 3,286 | +116% | 0 | 0 | — |
case-19 | pass→pass | 12,535 | 10,424 | -17% | 1 | 1 | 0% | 1,410 | 3,542 | +151% | 0 | 0 | — |
case-20 | pass→pass | 5,794 | 8,523 | +47% | 1 | 1 | 0% | 1,108 | 4,259 | +284% | 0 | 0 | — |
case-21 | pass→pass | 8,080 | 18,181 | +125% | 1 | 1 | 0% | 1,895 | 4,986 | +163% | 0 | 0 | — |
case-22 | pass→pass | 14,124 | 14,324 | +1% | 1 | 1 | 0% | 1,876 | 4,571 | +144% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +41 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.