Loading...
Loading...
Best practices and guidelines for TypeScript (2025-2026 Edition), focusing on TS 5.x+, modern type safety, and performance.
npx skill4agent add toilahuongg/shopify-agents-kit typescriptstrict: truetsconfig.json{
"compilerOptions": {
/* Type Safety */
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"useUnknownInCatchVariables": true,
"noUncheckedIndexedAccess": true, /* 2025 Essential: Prevents accessing undefined array indices */
"exactOptionalPropertyTypes": true, /* Stricter optional property checks */
/* Modules & Emit */
"module": "NodeNext", /* or "ESNext" for pure frontend */
"moduleResolution": "NodeNext", /* Aligns with modern Node.js ESM */
"target": "ES2022", /* Modern runtimes support recent ES features */
"skipLibCheck": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"verbatimModuleSyntax": true, /* Enforces strict import/export syntax (TS 5.0+) */
/* Developer Experience */
"allowSyntheticDefaultImports": true
}
}unknownanyanyunknown// ❌ Bad
function processData(input: any) {
input.doSomething(); // Runtime crash risk
}
// ✅ Good
function processData(input: unknown) {
if (typeof input === 'string') {
console.log(input.toUpperCase()); // Safe
} else if (isCustomType(input)) {
input.doSomething(); // Safe via type guard
}
}satisfiessatisfiestype Config = Record<string, string | number>;
const myConfig = {
port: 8080,
host: "localhost"
} satisfies Config;
// ✅ TS knows 'port' is a number directly, no casting needed.
myConfig.port.toFixed(2); readonlyinterface User {
readonly id: string;
readonly name: string;
tags: readonly string[]; // Immutable array
}
function printTags(tags: readonly string[]) {
// tags.push("new"); // ❌ Error: Property 'push' does not exist on type 'readonly string[]'
}type EventName = "click" | "hover";
type HandlerName = `on${Capitalize<EventName>}`; // "onClick" | "onHover"import type { ... }import { type ... }verbatimModuleSyntaxawait import(...)aszodasFunctionobject() => voidRecord<string, unknown>type Status = 'open' | 'closed'enum