typescript
Skill1 starsChanged 10 months agoMITView on GitHub
Complete TypeScript best practices guide including type definitions, generics, utility types, patterns, type safety, and type inference strategies. Use when defining types, creating generic components, ensuring type safety, or implementing type patterns.
- Sends data out
66 other projects use a version of this.
Adopted by
Most recently taken up by
- bbartling/open-fddtheir own version, first seen Nov 9, 2026
- TheLunchTrae/claude-code-configstheir own version, first seen Nov 8, 2026
- testdino-hq/google-styleguides-skillstheir own version, first seen Nov 8, 2026
- lobehub/lobehubtheir own version, first seen Nov 5, 2026
- its-ash/skillstheir own version, first seen Nov 1, 2026
- sentimony/skillstheir own version, first seen Nov 1, 2026
Used with
Projects with it also use msw, rust and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
thongdn-itSkillmsw
MSW (Mock Service Worker) best practices for API mocking in tests (formerly test-msw). This skill should be used when setting up MSW, writing request handlers, or mocking HTTP APIs. This skill does NOT cover general testing patterns (use test-vitest or test-tdd skills) or test methodology.
Also in 3 projects that use this
MicrosoftSkillrust
Use this guide when working on Rust changes in the FAST monorepo.
Also in 9 projects that use this
SupabaseSkillreact-hook-form
Correct React Hook Form usage anywhere in the monorepo — data flow, subscriptions,
Also in 3 projects that use this
VercelSkillreact
React renderer for json-render that turns JSON specs into React components. Use when working with @json-render/react, building React UIs from JSON, creating component catalogs, or rendering AI-generated specs.
Also in 10 projects that use this
leonaaardobSkilldrizzle
Complete Drizzle ORM documentation in markdown format. Use when working with Drizzle ORM - covers schema definition, queries, migrations, database connections (PostgreSQL, MySQL, SQLite), integrations (Neon, Supabase, PlanetScale, Cloudflare D1, Turso), column types, relations, transactions, and framework usage (Next.js, SvelteKit, Astro).
Also in 3 projects that use this
thongdn-itSkilltailwind
Tailwind CSS v4 performance optimization and best practices guidelines (formerly tailwindcss-v4-style). This skill should be used when writing, reviewing, or refactoring Tailwind CSS v4 code to ensure optimal build performance, minimal CSS output, and correct usage of v4 features. Triggers on tasks involving Tailwind configuration, @theme directive, utility classes, responsive design, dark mode, container queries, or CSS generation optimization.
Also in 5 projects that use this
- +1 more from thongdn-it
Other versions66 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 66
- lobehub/lobe-chat★ 84ksame name
- lobehub/lobehub★ 84ksame name
- recharts/recharts★ 28ksame name
- ccusage/ccusage★ 19ksame name
- ryoppippi/ccusage★ 19ksame name
- scalar/scalar★ 16ksame name
- prowler-cloud/prowler★ 15ksame name
- microsoft/fast★ 9.7ksame name
- epicenter-md/epicenter★ 4.8ksame name
- EpicenterHQ/epicenter★ 4.8ksame name
56 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository13 other files it gives its agents.
- api-developmentSkill
- docxSkill
- frontend-designSkill
- maplibre-gl-jsSkill
- nextjs-fullstackSkill
- pdfSkill
- performance-optimizationSkill
- pptxSkill
- prisma-databaseSkill
- shadcnSkill
- tanstackSkill
- testing-qaSkill
- xlsxSkill
The file
We split this skill into the rules it gives an agent
11 rules. 0 are common, 8 are distinctive, and 3 are very specific to this project.
0
Common
Most of the 52 edited versions we read keep these.
8
Distinctive
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 43
Avoid any - use unknown or specific types
- Distinctive: line 51
Always use strict TypeScript settings
- Distinctive: line 55
Prefer type guards over type assertions
- Distinctive: line 104
✅ EFFICIENT: Use built-in utility types
- Very specific: line 685
✅ Solution: Use unknown or specific types
- Distinctive: line 706
✅ Solution: Use type guards
- Very specific: line 816
No
any: - Use unknown or specific types - Distinctive: line 818
Strict mode: - Always use strict settings
- Distinctive: line 820
Type guards: - Prefer over assertions
- Distinctive: line 822
Consistent naming: - Follow naming conventions
- Distinctive: line 823
Document complex types: - When necessary
“Common” is measured: kept by at least 6 in 10 of the 52 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
TypeScript Skill
Skill Location: {project_path}/skills/typescript/
Comprehensive guide for writing type-safe TypeScript code, optimized for minimal token usage while maintaining type safety and developer experience.
When to Use This Skill (Trigger Patterns)
MUST apply this skill when:
- Defining TypeScript types and interfaces
- Creating generic components and functions
- Ensuring type safety
- Working with complex type transformations
- Using utility types
- Designing type-safe APIs
- Refactoring JavaScript to TypeScript
Trigger phrases:
- "define types for..."
- "make this type-safe"
- "create generic..."
- "add TypeScript to..."
- "fix type errors"
- "improve type definitions"
Core Principles
1. Type Over Any
Avoid any - use unknown or specific types
2. Type Inference
Let TypeScript infer types when possible
3. Strict Mode
Always use strict TypeScript settings
4. No Type Assertions
Prefer type guards over type assertions
Token-Saving Strategies
1. Use Self-Documenting Types
❌ INEFFICIENT:
// This interface represents a user object with their basic information
interface User {
// The unique identifier for the user
id: string;
// The user's full name
name: string;
}✅ EFFICIENT:
interface User {
id: string;
name: string;
email: string;
createdAt: Date;
}2. Assume TypeScript Knowledge
Don't explain:
- What
interfacevstypedoes - Basic generic syntax
- How type inference works
Focus on:
- Best practices
- Patterns
- Advanced scenarios
3. Use Utility Types
❌ INEFFICIENT: Re-implement common patterns
✅ EFFICIENT: Use built-in utility types
// Instead of manually creating partial type
interface UserUpdate {
name?: string;
email?: string;
role?: string;
}
// Use Partial
type UserUpdate = Partial<User>;Type Definitions
1. Interface vs Type
// Use interface for object shapes
interface User {
id: string;
name: string;
email: string;
createdAt: Date;
}
// Use type for unions, primitives, utility types
type ID = string | number;
type Status = "active" | "inactive" | "pending";
type UserWithPosts = User & { posts: Post[] };2. Model Types
// Base model
interface Model {
id: string;
createdAt: Date;
updatedAt: Date;
}
// Domain models
interface User extends Model {
name: string;
email: string;
role: UserRole;
}
interface Post extends Model {
title: string;
content: string;
authorId: string;
author: User;
status: PostStatus;
}
// Enums as union types
type UserRole = "user" | "admin" | "moderator";
type PostStatus = "draft" | "published" | "archived";3. API Types
// Request/Response types
interface ApiResponse<T> {
success: boolean;
data: T;
error?: ApiError;
}
interface ApiError {
message: string;
code?: string;
}
// API endpoints
interface UserCreateRequest {
name: string;
email: string;
role?: UserRole;
}
interface UserResponse extends User {}
// Usage
const response: ApiResponse<UserResponse> = {
success: true,
data: user,
};Generics
1. Generic Functions
// Generic function with constraints
function fetchData<T>(url: string): Promise<T> {
return fetch(url).then((r) => r.json());
}
// Generic function with default type
function createResponse<T = any>(data: T): ApiResponse<T> {
return { success: true, data };
}
// Generic with constraints
function ensureString<T extends string>(value: T): string {
return value;
}
// Multiple generics
function zip<A, B>(a: A[], b: B[]): [A, B][] {
return a.map((val, i) => [val, b[i]]);
}2. Generic Components
// Generic component props
interface TableProps<T> {
data: T[]
columns: ColumnDef<T>[]
onRowClick?: (row: T) => void
}
export function Table<T>({ data, columns, onRowClick }: TableProps<T>) {
return (
<table>
{data.map((row, i) => (
<tr key={i} onClick={() => onRowClick?.(row)}>
{columns.map((col, j) => (
<td key={j}>{col.accessor(row)}</td>
))}
</tr>
))}
</table>
)
}
// Usage
interface User {
id: string
name: string
email: string
}
const columns: ColumnDef<User>[] = [
{ header: 'Name', accessor: (u) => u.name },
{ header: 'Email', accessor: (u) => u.email }
]
<Table data={users} columns={columns} />3. Generic Hooks
// Generic hook
function useQuery<T>(key: string[], queryFn: () => Promise<T>) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
queryFn()
.then(setData)
.finally(() => setLoading(false));
}, [queryFn]);
return { data, loading };
}
// Usage
interface User {
id: string;
name: string;
}
const { data: users, loading } = useQuery<User[]>(["users"], () =>
fetch("/api/users").then((r) => r.json())
);Utility Types
1. Built-in Utility Types
// Partial - Makes all properties optional
type UserUpdate = Partial<User>;
// Required - Makes all properties required
type RequiredUser = Required<PartialUser>;
// Readonly - Makes all properties readonly
type ReadonlyUser = Readonly<User>;
// Record - Creates object type
type UserMap = Record<string, User>;
// Pick - Pick specific properties
type UserName = Pick<User, "name" | "email">;
// Omit - Omit specific properties
type UserWithoutId = Omit<User, "id">;
// Exclude - Exclude from union
type Status = "active" | "inactive" | "pending";
type ActiveStatus = Exclude<Status, "inactive" | "pending">;
// Extract - Extract from union
type StringKeys<T> = Extract<keyof T, string>;
// ReturnType - Get return type
type GetUser = () => User;
type UserResult = ReturnType<GetUser>;
// Parameters - Get parameter types
type CreateUser = (user: UserCreate) => Promise<User>;
type CreateUserParams = Parameters<CreateUser>[0];2. Custom Utility Types
// Deep partial
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
// Required keys
type RequiredKeys<T> = {
[K in keyof T]-?: T[K];
};
// Make specific keys required
type RequiredBy<T, K extends keyof T> = T & Required<Pick<T, K>>;
// Nullable
type Nullable<T> = T | null;
// Maybe
type Maybe<T> = T | null | undefined;
// ValueOf
type ValueOf<T> = T[keyof T];
// NonEmptyArray
type NonEmptyArray<T> = [T, ...T[]];Type Guards and Narrowing
1. Type Guards
// typeof guard
function processValue(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase(); // string
}
return value.toFixed(2); // number
}
// instanceof guard
class Dog {
bark() {}
}
class Cat {
meow() {}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
// Custom type guard
function isUser(obj: any): obj is User {
return "id" in obj && "name" in obj && "email" in obj;
}
// Usage
if (isUser(data)) {
console.log(data.name); // Type is User
}2. Discriminated Unions
type Success<T> = {
type: "success";
data: T;
};
type Error = {
type: "error";
message: string;
};
type Result<T> = Success<T> | Error;
function handleResult<T>(result: Result<T>) {
if (result.type === "success") {
console.log(result.data); // Type is T
} else {
console.log(result.message); // Type is string
}
}3. Type Predicates
function isArray<T>(value: unknown): value is T[] {
return Array.isArray(value);
}
function hasProperty<T extends object>(
obj: T,
key: PropertyKey
): key is keyof T {
return key in obj;
}Type Inference
1. Let TypeScript Infer
// Good - TypeScript infers return type
function getUser(id: string) {
return db.user.findUnique({ where: { id } });
}
// Better - Explicit when needed
function getUser(id: string): Promise<User | null> {
return db.user.findUnique({ where: { id } });
}
// Bad - Over-typed
function getUser(id: string): Promise<{
id: string;
name: string;
email: string;
createdAt: Date;
} | null> {
return db.user.findUnique({ where: { id } });
}2. Type Inference in Callbacks
// TypeScript infers item type
users.filter((user) => user.isActive);
// Explicit when inference fails
users.filter((user: User) => user.isActive);3. Generic Type Inference
// Type inferred from arguments
const users = await fetchData<User[]>("/api/users");
const user = await fetchData<User>("/api/users/1");Common Patterns
1. Builder Pattern
class QueryBuilder<T> {
private filters: string[] = [];
where(condition: string): this {
this.filters.push(condition);
return this;
}
build(): string {
return this.filters.join(" AND ");
}
}
const query = new QueryBuilder<User>()
.where("isActive = true")
.where("age > 18")
.build();2. Factory Pattern
interface UserFactory {
create(data: UserCreate): User;
}
class DefaultUserFactory implements UserFactory {
create(data: UserCreate): User {
return {
id: generateId(),
...data,
role: data.role || "user",
createdAt: new Date(),
updatedAt: new Date(),
};
}
}3. Repository Pattern
interface Repository<T> {
findById(id: string): Promise<T | null>;
findAll(): Promise<T[]>;
create(data: Omit<T, "id">): Promise<T>;
update(id: string, data: Partial<T>): Promise<T>;
delete(id: string): Promise<void>;
}
class UserRepository implements Repository<User> {
async findById(id: string): Promise<User | null> {
return db.user.findUnique({ where: { id } });
}
async findAll(): Promise<User[]> {
return db.user.findMany();
}
async create(data: Omit<User, "id">): Promise<User> {
return db.user.create({ data });
}
async update(id: string, data: Partial<User>): Promise<User> {
return db.user.update({ where: { id }, data });
}
async delete(id: string): Promise<void> {
await db.user.delete({ where: { id } });
}
}4. Event Emitter
type EventMap = {
userCreated: User;
userUpdated: User;
userDeleted: { id: string };
};
class EventEmitter<T extends Record<string, any>> {
private listeners: {
[K in keyof T]?: ((data: T[K]) => void)[];
} = {};
on<K extends keyof T>(event: K, listener: (data: T[K]) => void): void {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event]!.push(listener);
}
emit<K extends keyof T>(event: K, data: T[K]): void {
this.listeners[event]?.forEach((listener) => listener(data));
}
}
// Usage
const emitter = new EventEmitter<EventMap>();
emitter.on("userCreated", (user) => {
console.log(`User created: ${user.name}`);
});
emitter.emit("userCreated", user);Type-Safe API
1. Type-Safe API Client
interface ApiEndpoints {
"/api/users": {
GET: { response: User[] };
POST: { body: UserCreate; response: User };
};
"/api/users/[id]": {
GET: { response: User };
PUT: { body: Partial<User>; response: User };
DELETE: { response: { success: boolean } };
};
}
type ApiClient = {
[K in keyof ApiEndpoints]: {
[M in keyof ApiEndpoints[K]]: (
...args: ApiEndpoints[K][M] extends { body: infer B }
? [string | number, B]
: [string | number]
) => Promise<ApiEndpoints[K][M] extends { response: infer R } ? R : never>;
};
};
class Api implements ApiClient {
async get(url: string): Promise<any> {
return fetch(url).then((r) => r.json());
}
async post(url: string, body: any): Promise<any> {
return fetch(url, {
method: "POST",
body: JSON.stringify(body),
}).then((r) => r.json());
}
}2. Type-Safe React Hooks
function useApi<T>(
endpoint: string,
options?: { method?: "GET" | "POST" | "PUT" | "DELETE"; body?: any }
) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
fetch(endpoint, {
method: options?.method || "GET",
headers: { "Content-Type": "application/json" },
body: options?.body ? JSON.stringify(options.body) : undefined,
})
.then((r) => r.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [endpoint, options]);
return { data, loading, error };
}
// Usage
const { data: users } = useApi<User[]>("/api/users");Common Pitfalls & Solutions
❌ Problem: Using any type
✅ Solution: Use unknown or specific types
// Bad
function processData(data: any) {
return data.name;
}
// Good
function processData(data: { name: string }) {
return data.name;
}
// Better with generics
function processData<T extends { name: string }>(data: T): string {
return data.name;
}❌ Problem: Type assertions
✅ Solution: Use type guards
// Bad
const user = data as User;
// Good
if (isUser(data)) {
const user = data;
}❌ Problem: Duplicate types
✅ Solution: Reuse and compose types
// Bad
interface UserResponse {
id: string;
name: string;
email: string;
}
interface UserCreate {
id?: string;
name: string;
email: string;
}
// Good
interface User {
id: string;
name: string;
email: string;
}
type UserCreate = Omit<User, "id">;
type UserResponse = User;Token-Efficient Prompt Templates
Define Types
Define types for <DOMAIN>:
- Model types with base properties
- API request/response types
- Utility types for common operationsMake Type-Safe
Refactor <CODE> to be type-safe:
- Add type annotations
- Replace `any` with specific types
- Add type guardsCreate Generic
Create generic <COMPONENT/FUNCTION>:
- Type parameter(s)
- Constraints
- Type inferenceQuick Reference
// Type definitions
interface User {
id: string;
}
type Status = "active" | "inactive";
// Utility types
type PartialUser = Partial<User>;
type UserUpdate = Omit<User, "id">;
// Generics
function identity<T>(value: T): T {
return value;
}
// Type guards
function isUser(data: unknown): data is User {
return typeof data === "object" && "id" in data;
}
// Discriminated unions
type Result<T> =
| { type: "success"; data: T }
| { type: "error"; message: string };
// Type inference
const users = fetchData<User[]>("/api/users");Important Reminders
- No
any- Useunknownor specific types - Type inference - Let TypeScript infer when possible
- Strict mode - Always use strict settings
- Utility types - Reuse built-in utilities
- Type guards - Prefer over assertions
- Discriminated unions - For variant types
- Consistent naming - Follow naming conventions
- Document complex types - When necessary
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

