All skills
asyrafhussin avatar

/typescript-react-patterns

@e60e907

TypeScript best practices for React development. Use when writing typed React components, hooks, events, refs, or generic components. Triggers on tasks involving TypeScript errors, type definitions, props typing, or type-safe React patterns.

Use this Skill: https://skilld.dev/gh/asyrafhussin/agent-skills/typescript-react-patterns

This session only. Nothing lands on disk.

rulesgeneric-constraints.md

≈1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Generic Constraints with extends

Impact: MEDIUM (prevents invalid types from being passed to generic components and functions)

Unconstrained generics accept anything, including types that lack the properties your component needs. Use extends to constrain what T can be, and keyof to constrain keys to valid property names.

Incorrect

// ❌ Bad
// Unconstrained — accepts string, number, null, anything
interface ListProps<T> {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
}

function List<T>({ items, renderItem }: ListProps<T>) {
  return (
    <ul>
      {items.map((item, i) => (
        // Cannot use item.id as key — T might not have 'id'
        <li key={i}>{renderItem(item)}</li>
      ))}
    </ul>
  );
}

// Unconstrained key lookup — no guarantee key exists on obj
function getProperty<T>(obj: T, key: string): unknown {
  return (obj as any)[key]; // Forced to cast to any
}

Problems:

  • T could be a primitive, so accessing item.id would crash
  • key: string accepts any string, not just valid property names of T
  • Forced to use any casts to access properties, defeating TypeScript
  • No compile-time feedback when passing invalid types

Correct

// ✅ Good

// Constrain T to objects with an id
interface HasId {
  id: string | number;
}

function List<T extends HasId>({
  items,
  renderItem,
}: {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
}) {
  return (
    <ul>
      {items.map((item) => (
        // Safe — T is guaranteed to have .id
        <li key={item.id}>{renderItem(item)}</li>
      ))}
    </ul>
  );
}

// Constrain T to record-like objects
function ObjectTable<T extends Record<string, unknown>>({
  data,
  keys,
}: {
  data: T[];
  keys: (keyof T)[];
}) {
  return (
    <table>
      <thead>
        <tr>
          {keys.map((key) => (
            <th key={String(key)}>{String(key)}</th>
          ))}
        </tr>
      </thead>
      <tbody>
        {data.map((row, i) => (
          <tr key={i}>
            {keys.map((key) => (
              <td key={String(key)}>{String(row[key] ?? "")}</td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  );
}

// Constrain key to keyof T — type-safe property access
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key]; // No cast needed — return type is T[K]
}

interface User {
  id: number;
  name: string;
  email: string;
}

const user: User = { id: 1, name: "Alice", email: "alice@example.com" };
const name = getProperty(user, "name"); // type is string
const id = getProperty(user, "id"); // type is number
// getProperty(user, "age"); // Compile error — "age" is not keyof User

// Multiple constraints
function merge<T extends HasId, U extends Partial<T>>(base: T, updates: U): T {
  return { ...base, ...updates };
}

// Constrained component props
interface SortableListProps<T extends HasId & { sortOrder: number }> {
  items: T[];
  onReorder: (items: T[]) => void;
}

function SortableList<T extends HasId & { sortOrder: number }>({
  items,
  onReorder,
}: SortableListProps<T>) {
  const sorted = [...items].sort((a, b) => a.sortOrder - b.sortOrder);

  return (
    <ul>
      {sorted.map((item) => (
        <li key={item.id}>Item {item.id} (order: {item.sortOrder})</li>
      ))}
    </ul>
  );
}

Benefits:

  • T extends HasId guarantees .id exists, enabling safe key extraction
  • K extends keyof T restricts keys to valid property names with typed return values
  • T extends Record<string, unknown> ensures T is an object, not a primitive
  • Multiple constraints (T extends A & B) combine requirements cleanly

Reference: React TypeScript Cheatsheet — Generic Components

Source: SKILL.md on GitHub

No alerts16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill contains educational reference material and code documentation for TypeScript React development patterns. No security risks or malicious vectors were detected.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    30 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at e60e907. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated 7 months ago
metadata
{
  "author": "agent-skills",
  "version": "2.0.0"
}

README badge

README badge for asyrafhussin/agent-skills/typescript-react-patterns