Install
$ agentstack add skill-sagargupta16-claude-code-recipes-typescript-strict ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo 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.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
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 →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--nullandundefinedare their own typesstrictFunctionTypes-- function parameter types are checked strictlystrictBindCallApply--bind,call,applyare typed correctlystrictPropertyInitialization-- class properties must be initializednoImplicitAny-- no implicitanytypesnoImplicitThis--thismust have an explicit typealwaysStrict-- emit"use strict"in every file
No any Rules
- Never use
any-- useunknownwhen the type is truly unknown - Use
unknownand narrow -- type guards,instanceof,typeof - Use generics for flexible types --
function parse(input: string): T - Use
Recordoverobject-- more explicit - Suppress with
// @ts-expect-error(not// @ts-ignore) --@ts-expect-errorfails 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
- Use a literal
typeorkindfield as the discriminant - Handle all variants -- enable
noFallthroughCasesInSwitch - Use exhaustive checks -- add a
neverdefault 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
- Use Result types for expected failures -- validation, not-found, business rules
- Throw exceptions for unexpected failures -- programming errors, system failures
- Type your errors -- don't use
catch (e: any) - Use
causefor 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
anyto silence type errors -- find the correct type or useunknown - Type assertions (
as) without validation -- narrow with type guards instead - Enums -- prefer union types of string literals for better tree-shaking
Booleanconstructor 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.
- Author: Sagargupta16
- Source: Sagargupta16/claude-code-recipes
- License: MIT
- Homepage: https://sagargupta.online
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.