| name | typescript |
| description | TypeScript strict patterns and best practices. Trigger: When implementing or refactoring TypeScript in .ts/.tsx (types, interfaces, generics, const maps, type guards, removing any, tightening unknown).
|
| license | Apache-2.0 |
| metadata | {"author":"prowler-cloud","version":"1.0","scope":["root","ui"],"auto_invoke":"Writing TypeScript types/interfaces"} |
| allowed-tools | Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task |
Const Types Pattern (REQUIRED)
const STATUS = {
ACTIVE: "active",
INACTIVE: "inactive",
PENDING: "pending",
} as const;
type Status = (typeof STATUS)[keyof typeof STATUS];
type Status = "active" | "inactive" | "pending";
Why? Single source of truth, runtime values, autocomplete, easier refactoring.
Flat Interfaces (REQUIRED)
interface UserAddress {
street: string;
city: string;
}
interface User {
id: string;
name: string;
address: UserAddress;
}
interface Admin extends User {
permissions: string[];
}
interface User {
address: { street: string; city: string };
}
Never Use any
function parse(input: unknown): User {
if (isUser(input)) return input;
throw new Error("Invalid input");
}
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
function parse(input: any): any { }
Utility Types
Pick<User, "id" | "name">
Omit<User, "id">
Partial<User>
Required<User>
Readonly<User>
Record<string, User>
Extract<Union, "a" | "b">
Exclude<Union, "a">
NonNullable<T | null>
ReturnType<typeof fn>
Parameters<typeof fn>
Type Guards
function isUser(value: unknown): value is User {
return (
typeof value === "object" &&
value !== null &&
"id" in value &&
"name" in value
);
}
Coupled Optional Props (REQUIRED)
Do not model semantically coupled props as independent optionals — this allows invalid half-states that compile but break at runtime. Use discriminated unions with never to make invalid combinations impossible.
interface PaginationProps {
onPageChange?: (page: number) => void;
pageSize?: number;
currentPage?: number;
}
type ControlledPagination = {
controlled: true;
currentPage: number;
pageSize: number;
onPageChange: (page: number) => void;
};
type UncontrolledPagination = {
controlled: false;
currentPage?: never;
pageSize?: never;
onPageChange?: never;
};
type PaginationProps = ControlledPagination | UncontrolledPagination;
Key rule: If two or more props are only meaningful together, they belong to the same discriminated union branch. Mixing them as independent optionals shifts correctness responsibility from the type system to runtime guards.
Import Types
import type { User } from "./types";
import { createUser, type Config } from "./utils";