mcpbeat Sign in

Typescript Strict Agent Skill

TypeScript strict mode patterns with interfaces, type guards, generics, and utility types. Use when defining types, creating type-safe functions, handling nullable values, or implementing generic components.

1k tokens
context cost
the whole folder, loaded on every use
2
files
instructions only
0
copies elsewhere
how many repositories repackaged it
254
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/BlackBeltTechnology/pi-agent-dashboard --skill typescript-strict

What comes with it

597 bytes besides the instruction
SKILL.md.AGENTS.md

The instruction itself

10 sections, as written by the author

TypeScript Strict Patterns

Strict Configuration

// tsconfig.json essentials
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true
  }
}

Interface vs Type

// Use interface for objects that may be extended
interface Service {
  slug: string;
  name: string;
  price: number;
}

interface PremiumService extends Service {
  benefits: string[];
}

// Use type for unions, primitives, tuples
type Locale = 'pt-PT' | 'en' | 'tr' | 'es' | 'fr' | 'de';
type DeliveryMode = 'in-person' | 'online' | 'both';
type Coordinates = [number, number];

Type Guards

// Custom type guard
function isService(value: unknown): value is Service {
  return (
    typeof value === 'object' &&
    value !== null &&
    'slug' in value &&
    'name' in value
  );
}

// Discriminated unions
type Result<T> = 
  | { success: true; data: T }
  | { success: false; error: string };

function handleResult<T>(result: Result<T>) {
  if (result.success) {
    console.log(result.data); // TypeScript knows data exists
  } else {
    console.error(result.error); // TypeScript knows error exists
  }
}

Generic Patterns

// Generic data fetcher
async function fetchData<T>(url: string): Promise<T> {
  const res = await fetch(url);
  if (!res.ok) throw new Error('Failed to fetch');
  return res.json() as Promise<T>;
}

// Generic component props
interface ListProps<T> {
  items: T[];
  renderItem: (item: T, index: number) => React.ReactNode;
  keyExtractor: (item: T) => string;
}

function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
  return (
    <ul>
      {items.map((item, i) => (
        <li key={keyExtractor(item)}>{renderItem(item, i)}</li>
      ))}
    </ul>
  );
}

Utility Types

// Partial - all properties optional
type ServiceUpdate = Partial<Service>;

// Required - all properties required
type RequiredService = Required<Service>;

// Pick - select specific properties
type ServicePreview = Pick<Service, 'slug' | 'name'>;

// Omit - exclude properties
type ServiceWithoutPrice = Omit<Service, 'price'>;

// Record - key-value mapping
type LocaleMessages = Record<Locale, Record<string, string>>;

// Extract/Exclude for unions
type OnlineDelivery = Extract<DeliveryMode, 'online' | 'both'>;

Nullable Handling

// Non-null assertion (use sparingly)
const element = document.getElementById('root')!;

// Optional chaining + nullish coalescing
const name = user?.profile?.name ?? 'Anonymous';

// Type narrowing
function processValue(value: string | null | undefined) {
  if (value == null) return; // Handles both null and undefined
  console.log(value.toUpperCase()); // value is string
}

Component Props Patterns

// Props with children
interface ContainerProps {
  children: React.ReactNode;
  className?: string;
}

// Props extending HTML elements
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'primary' | 'secondary';
  loading?: boolean;
}

// Polymorphic component
interface BoxProps<T extends React.ElementType> {
  as?: T;
  children: React.ReactNode;
}

type BoxPropsWithRef<T extends React.ElementType> = BoxProps<T> &
  Omit<React.ComponentPropsWithoutRef<T>, keyof BoxProps<T>>;

Const Assertions

// Immutable arrays and objects
const LOCALES = ['pt-PT', 'en', 'tr', 'es', 'fr', 'de'] as const;
type Locale = typeof LOCALES[number]; // 'pt-PT' | 'en' | ...

const THEME_CONFIG = {
  studio: { bg: '#ffffff', accent: '#000000' },
  earth: { bg: '#faf9f6', accent: '#8b7355' },
} as const;

Zod Integration

import { z } from 'zod';

// Infer types from Zod schemas
const ServiceSchema = z.object({
  slug: z.string(),
  name: z.string(),
  price: z.number().positive(),
});

type Service = z.infer<typeof ServiceSchema>;

How to use it

Copy the folder

Take blackbelttechnology/typescript-strict from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.