
Typescript Strict
- 42 installs
- 49 repo stars
- Updated August 4, 2026
- laurigates/claude-plugins
Helps with ai & agent building tasks.
About
typescript-strict is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- typescript-strict
- AI & Agent Building
- AI-coding skill
Typescript Strict by the numbers
- 42 all-time installs (skills.sh)
- Ranked #8,023 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/laurigates/claude-plugins --skill typescript-strictAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 42 |
|---|---|
| repo stars | ★ 49 |
| Last updated | August 4, 2026 |
| Repository | laurigates/claude-plugins ↗ |
What it does
Helps with ai & agent building tasks.
Files
TypeScript Strict Mode
Modern TypeScript configuration with strict type checking for maximum safety and developer experience. This guide focuses on TypeScript 5.x best practices for 2025.
When to Use This Skill
| Use this skill when... | Use another approach when... |
|---|---|
| Setting up a new TypeScript project | Debugging runtime errors (use debugger) |
| Migrating to stricter type safety | Configuring build tools (use bundler docs) |
| Choosing moduleResolution strategy | Writing application logic |
| Enabling noUncheckedIndexedAccess | Optimizing bundle size (use bundler skills) |
Core Expertise
What is Strict Mode?
- Type safety: Catch more bugs at compile time
- Better IDE experience: Improved autocomplete and refactoring
- Maintainability: Self-documenting code with explicit types
- Modern defaults: Align with current TypeScript best practices
Key Capabilities
- Strict null checking
- Strict function types
- No implicit any
- No unchecked indexed access
- Proper module resolution
- Modern import/export syntax enforcement
Recommended tsconfig.json (2025)
Minimal Production Setup
{
"compilerOptions": {
// Type Checking
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
// Modules
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": false,
"verbatimModuleSyntax": true,
// Emit
"target": "ES2022",
"lib": ["ES2023", "DOM", "DOM.Iterable"],
"outDir": "dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"removeComments": false,
"noEmit": false,
// Interop
"isolatedModules": true,
"allowJs": false,
"checkJs": false,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "build"]
}Strict Flags Explained
strict: true (Umbrella Flag)
Enables all strict type-checking options:
{
"strict": true
// Equivalent to:
// "noImplicitAny": true,
// "strictNullChecks": true,
// "strictFunctionTypes": true,
// "strictBindCallApply": true,
// "strictPropertyInitialization": true,
// "noImplicitThis": true,
// "alwaysStrict": true
}Always enable `strict: true` for new projects.
Additional Strict Flags (Recommended for 2025)
| Flag | Purpose |
|---|---|
noUncheckedIndexedAccess | Index signatures return `T \ |
noImplicitOverride | Require override keyword for overridden methods |
noPropertyAccessFromIndexSignature | Force bracket notation for index signatures |
noFallthroughCasesInSwitch | Prevent fallthrough in switch statements |
exactOptionalPropertyTypes | Optional properties cannot be set to undefined explicitly |
noUncheckedIndexedAccess (Essential)
// With noUncheckedIndexedAccess
const users: Record<string, User> = {};
const user = users['john'];
// Type: User | undefined (correct - must check before use)
if (user) {
console.log(user.name); // Type narrowed to User
}Always enable this flag to prevent runtime errors.
Module Resolution
Choosing a Strategy
| Strategy | Use For | Extensions Required |
|---|---|---|
Bundler | Vite, Webpack, Bun projects | No |
NodeNext | Node.js libraries and servers | Yes (.js) |
moduleResolution: "Bundler" (Vite/Bun)
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "Bundler"
}
}- No file extensions required in imports
- JSON imports without assertions
- Package.json
exportsfield support
moduleResolution: "NodeNext" (Node.js)
{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext"
}
}- Respects package.json
type: "module" - Requires explicit
.jsextensions (even for.tsfiles) - Supports conditional exports
verbatimModuleSyntax (Recommended for 2025)
Prevents TypeScript from rewriting imports/exports.
{
"compilerOptions": {
"verbatimModuleSyntax": true
}
}// Error: 'User' is a type and must be imported with 'import type'
import { User } from './types';
// Correct
import type { User } from './types';
// Correct (mixed import)
import { fetchUser, type User } from './api';Replaces deprecated importsNotUsedAsValues and preserveValueImports.
Agentic Optimizations
| Context | Command |
|---|---|
| Check errors | bunx tsc --noEmit |
| Check single file | bunx tsc --noEmit src/utils.ts |
| Show config | bunx tsc --showConfig |
| Check module resolution | `bunx tsc --showConfig \ |
Quick Reference
Recommended Flags
| Flag | Value | Category |
|---|---|---|
strict | true | Type Checking |
noUncheckedIndexedAccess | true | Type Checking |
noImplicitOverride | true | Type Checking |
noPropertyAccessFromIndexSignature | true | Type Checking |
noFallthroughCasesInSwitch | true | Type Checking |
module | ESNext / NodeNext | Modules |
moduleResolution | Bundler / NodeNext | Modules |
verbatimModuleSyntax | true | Modules |
target | ES2022 | Emit |
isolatedModules | true | Interop |
skipLibCheck | true | Interop |
For detailed examples, advanced patterns, and best practices, see REFERENCE.md.
References
- TypeScript Handbook: https://www.typescriptlang.org/docs/handbook/intro.html
- TSConfig Reference: https://www.typescriptlang.org/tsconfig
- Strict Mode Guide: https://www.typescriptlang.org/tsconfig#strict
- Module Resolution: https://www.typescriptlang.org/docs/handbook/module-resolution.html
- Best Practices: https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html
TypeScript Strict Mode - Reference
Detailed reference material for TypeScript strict mode configuration.
Full tsconfig.json Templates
Vite/Bun Project (Bundler)
{
"compilerOptions": {
// Type Checking - Maximum strictness
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"exactOptionalPropertyTypes": true,
// Modules (Bundler for Vite/Bun)
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": false,
"verbatimModuleSyntax": true,
// Emit (Vite handles bundling)
"target": "ES2022",
"lib": ["ES2023", "DOM", "DOM.Iterable"],
"jsx": "preserve", // Vite handles JSX
"noEmit": true, // Vite handles emit
// Interop
"isolatedModules": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
// Path Mapping
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"]
}
},
"include": ["src/**/*", "vite.config.ts"],
"exclude": ["node_modules", "dist"]
}Node.js Library (NodeNext)
{
"compilerOptions": {
// Type Checking
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
// Modules (NodeNext for Node.js)
"module": "NodeNext",
"moduleResolution": "NodeNext",
"resolveJsonModule": true,
"allowSyntheticDefaultImports": false,
"esModuleInterop": true,
"verbatimModuleSyntax": true,
// Emit (Node.js library)
"target": "ES2022",
"lib": ["ES2023"],
"outDir": "dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
// Interop
"isolatedModules": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}Strict Flags Detailed Examples
noImplicitAny
Disallows variables with implicit any type.
// Error with noImplicitAny
function add(a, b) {
// ^ Error: Parameter 'a' implicitly has an 'any' type
return a + b;
}
// Correct
function add(a: number, b: number): number {
return a + b;
}strictNullChecks
null and undefined are distinct from other types.
// Error with strictNullChecks
const name: string = null;
// ^^^^ Error: Type 'null' is not assignable to type 'string'
// Correct
const name: string | null = null;
// Correct (handle null explicitly)
function greet(name: string | null): string {
if (name === null) {
return 'Hello, stranger!';
}
return `Hello, ${name}!`;
}strictFunctionTypes
Function parameter types are checked contravariantly.
type Logger = (msg: string | number) => void;
// Error with strictFunctionTypes
const log: Logger = (msg: string) => console.log(msg);
// ^^^^^^^^^^^^^ Error: Type '(msg: string) => void' is not assignable
// Correct
const log: Logger = (msg: string | number) => console.log(msg);strictBindCallApply
Check that bind, call, and apply are invoked correctly.
function greet(name: string, age: number) {
console.log(`${name} is ${age} years old`);
}
// Error with strictBindCallApply
greet.call(undefined, 'John', '25');
// ^^^^ Error: Argument of type 'string' is not assignable to 'number'
// Correct
greet.call(undefined, 'John', 25);strictPropertyInitialization
Class properties must be initialized.
class User {
// Error with strictPropertyInitialization
name: string;
// ^^^^^^ Error: Property 'name' has no initializer
// Correct (initialize in constructor)
name: string;
constructor(name: string) {
this.name = name;
}
// Correct (default value)
age: number = 0;
// Correct (definitely assigned assertion)
id!: number;
}noImplicitThis
Disallow this with implicit any type.
// Error with noImplicitThis
function logName() {
console.log(this.name);
// ^^^^ Error: 'this' implicitly has type 'any'
}
// Correct (explicit this parameter)
function logName(this: { name: string }) {
console.log(this.name);
}noImplicitOverride
Require override keyword for overridden methods.
class Base {
greet() {
console.log('Hello');
}
}
class Derived extends Base {
// Error with noImplicitOverride
greet() {
// ^^^^^ Error: This member must have an 'override' modifier
console.log('Hi');
}
// Correct
override greet() {
console.log('Hi');
}
}noPropertyAccessFromIndexSignature
Force bracket notation for index signatures.
type User = {
name: string;
[key: string]: string;
};
const user: User = { name: 'John', email: 'john@example.com' };
// Error with noPropertyAccessFromIndexSignature
console.log(user.email);
// ^^^^^ Error: Property 'email' comes from index signature, use bracket notation
// Correct
console.log(user['email']);
// Also correct (explicit property)
console.log(user.name);noFallthroughCasesInSwitch
Prevent fallthrough in switch statements.
function getDiscount(role: string): number {
switch (role) {
case 'admin':
return 0.5;
// Error with noFallthroughCasesInSwitch
case 'user':
// ^^^^ Error: Fallthrough case in switch
console.log('User discount');
case 'guest':
return 0.1;
}
}
// Correct
function getDiscount(role: string): number {
switch (role) {
case 'admin':
return 0.5;
case 'user':
console.log('User discount');
return 0.2; // Explicit return
case 'guest':
return 0.1;
default:
return 0;
}
}exactOptionalPropertyTypes
Optional properties cannot be set to undefined explicitly.
type User = {
name: string;
age?: number; // Type: number | undefined (implicit)
};
// Error with exactOptionalPropertyTypes
const user: User = { name: 'John', age: undefined };
// ^^^^^^^^^ Error: Type 'undefined' is not assignable
// Correct (omit property)
const user: User = { name: 'John' };
// Correct (assign a value)
const user2: User = { name: 'Jane', age: 25 };Module Resolution Details
moduleResolution: "Bundler" (Vite/Bun)
Use for projects with bundlers (Vite, Webpack, Bun).
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "Bundler"
}
}Features:
- No file extensions required in imports
- JSON imports without assertions
- Package.json
exportsfield support - Optimized for bundlers
// Works with Bundler
import config from './config.json';
import { add } from './utils'; // No .ts extensionmoduleResolution: "NodeNext" (Node.js)
Use for Node.js libraries and servers.
{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext"
}
}Features:
- Respects package.json
type: "module" - Requires explicit
.jsextensions (even for.tsfiles) - Supports conditional exports
- Aligned with Node.js ESM behavior
// Works with NodeNext (note .js extension)
import { add } from './utils.js';
import config from './config.json' assert { type: 'json' };package.json:
{
"type": "module",
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
}
}Path Mapping
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@utils/*": ["src/utils/*"]
}
}
}Usage:
// Path aliases keep imports clean
import { Button } from '@components/Button';Vite/Bun configuration:
// vite.config.ts
import { defineConfig } from 'vite';
import path from 'path';
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
},
},
});Migrating to Strict Mode
Step 1: Enable Gradually
{
"compilerOptions": {
// Start with these
"noImplicitAny": true,
"strictNullChecks": false, // Enable later
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": false, // Enable later
"noImplicitThis": true,
"alwaysStrict": true
}
}Step 2: Fix Errors Incrementally
# Check errors without emitting
bunx tsc --noEmit
# Fix files one at a time
bunx tsc --noEmit src/utils.tsStep 3: Enable Remaining Flags
{
"compilerOptions": {
"strict": true, // Enable all at once
"noUncheckedIndexedAccess": true
}
}Step 4: Optional Strict Flags
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"exactOptionalPropertyTypes": true
}
}Common Patterns
Handling Null/Undefined
// Non-null assertion (use sparingly)
const element = document.getElementById('app')!;
// Optional chaining
const name = user?.profile?.name;
// Nullish coalescing
const displayName = user?.name ?? 'Anonymous';
// Type guard
function isUser(value: unknown): value is User {
return typeof value === 'object' && value !== null && 'name' in value;
}Index Signature Safety
// Unsafe
const value = obj[key]; // Type: T (wrong)
// Safe with noUncheckedIndexedAccess
const value = obj[key]; // Type: T | undefined
if (value !== undefined) {
// Type: T
console.log(value);
}
// Safe with assertion
const value = obj[key];
if (value === undefined) throw new Error('Key not found');
// Type: T (narrowed)Troubleshooting
Too Many Errors
# Enable flags gradually
# Start with noImplicitAny, then add others
# Use @ts-expect-error for temporary fixes
// @ts-expect-error - TODO: Fix this type
const value: string = null;Library Types Missing
# Install type definitions
bun add --dev @types/node @types/react
# Skip type checking for libraries
{
"compilerOptions": {
"skipLibCheck": true
}
}Module Resolution Errors
// Bundler: No extension needed
import { add } from './utils';
// NodeNext: Requires .js extension
import { add } from './utils.js';
// Check moduleResolution setting
bunx tsc --showConfig | grep moduleResolution