AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Typescript Strict

skill-sagargupta16-claude-code-recipes-typescript-strict · by Sagargupta16

Strict TypeScript conventions covering strict mode config, no-any rules, utility types, discriminated unions, branded types, and error handling patterns. Use when writing TypeScript, tightening types, or migrating code to strict mode.

No reviews yet
0 installs
31 views
0.0% view→install

Install

$ agentstack add skill-sagargupta16-claude-code-recipes-typescript-strict

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-sagargupta16-claude-code-recipes-typescript-strict)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Typescript Strict? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

TypeScript Strict

> Strict TypeScript conventions: strict mode config, no-any rules, utility types, discriminated unions, branded types, and error handling patterns.

Strict Mode Configuration

Always enable strict mode. Use this tsconfig.json base:

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "noFallthroughCasesInSwitch": true,
    "forceConsistentCasingInFileNames": true,
    "exactOptionalPropertyTypes": true,
    "verbatimModuleSyntax": true
  }
}

What strict: true Enables

  • strictNullChecks -- null and undefined are their own types
  • strictFunctionTypes -- function parameter types are checked strictly
  • strictBindCallApply -- bind, call, apply are typed correctly
  • strictPropertyInitialization -- class properties must be initialized
  • noImplicitAny -- no implicit any types
  • noImplicitThis -- this must have an explicit type
  • alwaysStrict -- emit "use strict" in every file

No any Rules

  1. Never use any -- use unknown when the type is truly unknown
  2. Use unknown and narrow -- type guards, instanceof, typeof
  3. Use generics for flexible types -- function parse(input: string): T
  4. Use Record over object -- more explicit
  5. Suppress with // @ts-expect-error (not // @ts-ignore) -- @ts-expect-error fails if the error is fixed
// Bad
function parse(data: any): any {
  return JSON.parse(data);
}

// Good
function parse(data: string): unknown {
  return JSON.parse(data);
}

// Good -- with type guard
function isUser(value: unknown): value is User {
  return (
    typeof value === "object" &&
    value !== null &&
    "id" in value &&
    "email" in value
  );
}

const data: unknown = parse(input);
if (isUser(data)) {
  console.log(data.email); // typed as User
}

Utility Types

Use built-in utility types instead of manual type construction:

| Utility | Use Case | Example | |---------|----------|---------| | Partial | All properties optional | Update DTOs: Partial | | Required | All properties required | Override optionals | | Pick | Select specific properties | Pick | | Omit | Remove specific properties | Omit | | Readonly | All properties readonly | Immutable state | | Record | Object with known key/value types | Record | | Extract | Extract union members matching U | Extract | | Exclude | Remove union members matching U | Exclude | | NonNullable | Remove null/undefined | NonNullable -> string | | ReturnType | Extract return type of function | ReturnType | | Awaited | Unwrap Promise type | Awaited> -> User |

// Compose utility types for DTOs
interface User {
  id: string;
  email: string;
  name: string;
  password: string;
  role: "admin" | "user";
  createdAt: Date;
}

type CreateUserInput = Omit;
type UpdateUserInput = Partial>;
type PublicUser = Omit;

Discriminated Unions

Use discriminated unions for type-safe state management and variant types:

// Define a discriminated union with a literal "type" field
type ApiResult =
  | { status: "loading" }
  | { status: "success"; data: T }
  | { status: "error"; error: Error };

function renderResult(result: ApiResult) {
  switch (result.status) {
    case "loading":
      return ;
    case "success":
      return ;  // data is available
    case "error":
      return ;  // error is available
  }
}

Rules

  1. Use a literal type or kind field as the discriminant
  2. Handle all variants -- enable noFallthroughCasesInSwitch
  3. Use exhaustive checks -- add a never default case
// Exhaustive switch -- compile error if a variant is missed
function assertNever(value: never): never {
  throw new Error(`Unhandled variant: ${JSON.stringify(value)}`);
}

function handleEvent(event: AppEvent) {
  switch (event.type) {
    case "click":
      return handleClick(event);
    case "keypress":
      return handleKeypress(event);
    default:
      return assertNever(event); // Compile error if new variant is added
  }
}

Common Patterns

// Action types for reducers
type Action =
  | { type: "SET_USER"; payload: User }
  | { type: "SET_ERROR"; payload: string }
  | { type: "RESET" };

// API responses
type Response =
  | { ok: true; data: User[] }
  | { ok: false; error: string };

// Form field types
type FormField =
  | { kind: "text"; value: string; maxLength?: number }
  | { kind: "number"; value: number; min?: number; max?: number }
  | { kind: "select"; value: string; options: string[] }
  | { kind: "checkbox"; value: boolean };

Branded Types

Use branded types to prevent mixing semantically different values that share a primitive type:

// Define branded types
type UserId = string & { readonly __brand: "UserId" };
type OrderId = string & { readonly __brand: "OrderId" };
type Email = string & { readonly __brand: "Email" };

// Constructor functions with validation
function UserId(id: string): UserId {
  if (!id.startsWith("usr_")) throw new Error("Invalid user ID");
  return id as UserId;
}

function Email(value: string): Email {
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
    throw new Error("Invalid email");
  }
  return value as Email;
}

// Type safety -- can't mix them up
function getUser(id: UserId): Promise { /* ... */ }
function getOrder(id: OrderId): Promise { /* ... */ }

const userId = UserId("usr_abc123");
const orderId = OrderId("ord_xyz789");

getUser(userId);    // OK
getUser(orderId);   // Compile error -- OrderId is not UserId

Error Handling Patterns

Result Type

Use a Result type instead of throwing exceptions for expected errors:

type Result =
  | { ok: true; value: T }
  | { ok: false; error: E };

// Helper constructors
function ok(value: T): Result {
  return { ok: true, value };
}

function err(error: E): Result {
  return { ok: false, error };
}

// Usage
async function createUser(input: CreateUserInput): Promise> {
  const existing = await db.findByEmail(input.email);
  if (existing) {
    return err({ code: "EMAIL_EXISTS", message: "Email already registered" });
  }

  const user = await db.create(input);
  return ok(user);
}

// Caller handles both cases
const result = await createUser(input);
if (result.ok) {
  console.log("Created:", result.value.id);
} else {
  console.error("Failed:", result.error.message);
}

Custom Error Classes

class AppError extends Error {
  constructor(
    message: string,
    public readonly code: string,
    public readonly statusCode: number = 500,
    public readonly cause?: unknown,
  ) {
    super(message);
    this.name = this.constructor.name;
  }
}

class NotFoundError extends AppError {
  constructor(resource: string, id: string) {
    super(`${resource} not found: ${id}`, "NOT_FOUND", 404);
  }
}

class ValidationError extends AppError {
  constructor(
    message: string,
    public readonly fields: Record,
  ) {
    super(message, "VALIDATION_ERROR", 400);
  }
}

Rules

  1. Use Result types for expected failures -- validation, not-found, business rules
  2. Throw exceptions for unexpected failures -- programming errors, system failures
  3. Type your errors -- don't use catch (e: any)
  4. Use cause for error chains -- new Error("Failed to save", { cause: originalError })

Type Narrowing Techniques

// typeof
function format(value: string | number): string {
  if (typeof value === "string") return value.trim();
  return value.toFixed(2);
}

// instanceof
function handleError(error: unknown): string {
  if (error instanceof AppError) return error.code;
  if (error instanceof Error) return error.message;
  return String(error);
}

// in operator
function getArea(shape: Circle | Rectangle): number {
  if ("radius" in shape) return Math.PI * shape.radius ** 2;
  return shape.width * shape.height;
}

// Custom type guard
function isDefined(value: T | null | undefined): value is T {
  return value !== null && value !== undefined;
}

const users = [getUser(1), getUser(2), null].filter(isDefined);
// type: User[]

Anti-patterns

  • Using any to silence type errors -- find the correct type or use unknown
  • Type assertions (as) without validation -- narrow with type guards instead
  • Enums -- prefer union types of string literals for better tree-shaking
  • Boolean constructor as filter -- .filter(Boolean) loses type narrowing; use .filter(isDefined)
  • Ignoring strictNullChecks -- the single most valuable strict check
  • Overusing ! non-null assertion -- it lies to the compiler; handle the null case
  • Complex conditional types in application code -- keep them in library/utility code

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.