
typescript-patterns
by arichardsmith
SKILL.md
name: typescript-patterns description: Conventions for TypeScript types, interfaces, assertions, and type safety. Use when writing or reviewing TypeScript code.
TypeScript Patterns Skill
Best practices for types, interfaces, assertions, and type safety.
Use Explicit Return Types
// ✅ Explicit return type
function calculateTotal(items: OrderItem[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}
// ❌ Inferred return type
function calculateTotal(items: OrderItem[]) {
return items.reduce((sum, item) => sum + item.price, 0);
}
Why: Explicit return types catch when we try to return incorrect data. They also speed up type checking.
Runtime Type Assertions
Never hard cast from JSON.parse. Validate at runtime.
// ❌ Hard cast
const value: MyType = JSON.parse(message);
// ✅ Runtime assertion
function isMyType(value: unknown): value is MyType {
return typeof value === 'object' &&
value !== null &&
typeof (<MyType>value).prop === 'string';
}
const value = JSON.parse(message);
assert(isMyType(value), 'Invalid message format');
Type Assertion Functions
// Parameter: 'value' with 'unknown' type
// Always return boolean, never throw
function isStrategy(value: unknown): value is Strategy {
return typeof value === 'object' &&
value !== null &&
typeof (<Strategy>value).name === 'string';
}
// Use with assert
assert(isStrategy(value), 'Value is not a valid Strategy');
Interfaces vs Types
// Interface for module-scope object types
export interface Product {
id: string;
name: string;
price: number;
}
// Type when combining or modifying existing types
type StockedProduct = Exclude<Product, "name"> & { stock: StockStatus }
// Type for unions
type Status = 'pending' | 'active' | 'inactive';
Casting Syntax
// ✅ 'as' syntax
const x = y as number;
// ❌ Angle bracket syntax
const x = <number>y;
const config = <ConfigType>JSON.parse(json);
Interface Conventions
- No
Iprefix orDatasuffix - Properties in alphabetical order
- Think of interfaces as nouns or adjectives (Shippable, Refundable)
// Adjective interfaces
interface Shippable {
shipping_address: string;
shipping_cost: number;
}
// Concrete interface
interface Order extends Shippable {
id: string;
total: number;
}
Enums
Never use typescript enums. Instead use objects with text values and infer the value type from the object.
export const OrderStatus = {
confirmed: "confirmed",
paid: "paid",
shipped: "shipped"
}
export type OrderStatus = (typeof OrderStatus)[keyof typeof OrderStatus];
Type Shadowing
It is ok (infact prefered) to shadow enums and validation schemas with the resulting type. However, do not type shadow in other cases.
// ✅ schema shadowing
export const Product = z.object({
id: z.string(),
name: z.string(),
price: z.number().min(0)
})
export type Product = z.infer<typeof Product>;
// ❌ other shadowing
export const Config = {
allow_net: true,
units: "standard"
}
export type Config = {
allow_next: false,
units: Unit
}
Iteration
// ✅ for...of loop
for (const item of items) {
processItem(item);
}
// ❌ forEach
items.forEach((item) => {
processItem(item);
});
Why: for...of works with break, continue, return, await, and has better debugging/stack traces.
Use map/filter/reduce for transformations, not side effects.
Import Style
// ✅ Namespace imports
import * as mongodb from 'mongodb';
import * as Types from './types/index.js';
// ❌ Default imports
import MongoDB from 'mongodb';
Organization
- Keep types with related code (not in
types/directories) - Only export types that are part of public API
- Use
ReturnTypeandParametersto access private types
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon