Article
TypeScript Strict Mode Battles: When AI-Generated Code Won't Compile
Type 'any' is not allowed, property does not exist on type, and 300+ TypeScript errors blocking your build—why AI struggles with strict TypeScript and how to fix it.
TypeScript Strict Mode Battles: When AI-Generated Code Won't Compile
You generated a beautiful application with Bolt or v0. It works perfectly in the preview. Then you try to build for production and TypeScript explodes: 287 type errors across 43 files. Your heart sinks as you scroll through pages of TS2345, TS2322, TS7006, and the dreaded "Type 'any' is not allowed" errors.
This is one of the most frustrating aspects of vibe coding: AI assistants write code quickly, but they often ignore type safety entirely.
Why AI Tools Struggle with TypeScript
AI coding assistants are trained on millions of code examples from GitHub, Stack Overflow, and documentation. The problem? Most public code uses loose TypeScript configurations or plain JavaScript. The AI learns patterns like:
// Common in training data, but terrible TypeScript
function processData(data: any) {
return data.map((item: any) => item.value);
}
When you enable strict: true in your tsconfig.json, this code becomes unacceptable, and the AI doesn't know how to fix it.
The Most Common TypeScript Errors in AI Code
TS2322: Type Assignment Errors
Type 'string | undefined' is not assignable to type 'string'.
The Problem:
// ❌ AI assumes data always exists
interface User {
name: string;
email: string;
}
const user: User = {
name: getUserName(), // Returns string | undefined
email: getEmail(), // Returns string | undefined
};
The Fix:
// ✅ Handle optional values properly
interface User {
name: string;
email: string;
}
const userName = getUserName();
const userEmail = getEmail();
if (!userName || !userEmail) {
throw new Error('Missing user data');
}
const user: User = {
name: userName, // TypeScript knows it's string
email: userEmail, // TypeScript knows it's string
};
// Or use nullish coalescing
const user: User = {
name: getUserName() ?? 'Anonymous',
email: getEmail() ?? 'no-email@example.com',
};
TS2345: Argument Type Errors
Argument of type 'number' is not assignable to parameter of type 'string'.
The Problem:
// ❌ Mismatched types
function formatId(id: string) {
return `ID-${id}`;
}
const userId = 12345;
formatId(userId); // Error!
The Fix:
// ✅ Option 1: Convert types
formatId(userId.toString());
// ✅ Option 2: Use union types
function formatId(id: string | number) {
return `ID-${id}`;
}
// ✅ Option 3: Use generic types
function formatId<T extends string | number>(id: T) {
return `ID-${id}`;
}
TS2339: Property Does Not Exist
Property 'user' does not exist on type '{}'.
The Problem:
// ❌ Empty object with no type
const data = {};
data.user = 'John'; // Error!
// ❌ API response typed as 'any'
const response = await fetch('/api/user');
const data = await response.json(); // type: any
console.log(data.user.name); // No error, but might crash at runtime
The Fix:
// ✅ Define proper types
interface UserData {
user: string;
}
const data: UserData = {
user: 'John',
};
// ✅ Type API responses
interface ApiResponse {
user: {
name: string;
email: string;
};
}
const response = await fetch('/api/user');
const data: ApiResponse = await response.json();
console.log(data.user.name); // Type-safe
TS7006: Implicit 'any' Parameter
Parameter 'item' implicitly has an 'any' type.
The Problem:
// ❌ No type for callback parameter
const doubled = numbers.map(n => n * 2); // 'n' has implicit 'any' type
The Fix:
// ✅ Explicit type annotation
const numbers: number[] = [1, 2, 3];
const doubled = numbers.map((n: number) => n * 2);
// ✅ TypeScript infers from array type
const numbers: number[] = [1, 2, 3];
const doubled = numbers.map(n => n * 2); // 'n' inferred as number
// ✅ Generic type for flexibility
function processItems<T>(items: T[], callback: (item: T) => void) {
items.forEach(callback);
}
TS2741: Missing Properties
Property 'id' is missing in type but required in type 'User'.
The Problem:
// ❌ Incomplete object
interface User {
id: string;
name: string;
email: string;
createdAt: Date;
}
const user: User = {
name: 'John',
email: 'john@example.com',
}; // Error: missing 'id' and 'createdAt'
The Fix:
// ✅ Option 1: Provide all properties
const user: User = {
id: crypto.randomUUID(),
name: 'John',
email: 'john@example.com',
createdAt: new Date(),
};
// ✅ Option 2: Make properties optional
interface User {
id: string;
name: string;
email: string;
createdAt?: Date; // Optional
}
// ✅ Option 3: Use Partial<T>
const partialUser: Partial<User> = {
name: 'John',
email: 'john@example.com',
};
// ✅ Option 4: Use Pick<T, Keys>
const userNameAndEmail: Pick<User, 'name' | 'email'> = {
name: 'John',
email: 'john@example.com',
};
The "Type 'any' is Not Allowed" Crisis
Many production codebases enable no-explicit-any in their linting rules. AI-generated code loves using 'any':
// ❌ AI-generated code full of 'any'
function fetchData(url: string): Promise<any> {
return fetch(url).then((res: any) => res.json());
}
function processUser(data: any) {
return data.users.map((user: any) => ({
id: user.id,
name: user.name,
}));
}
The Systematic Fix
// ✅ Define proper types
interface User {
id: string;
name: string;
email: string;
}
interface ApiResponse {
users: User[];
}
async function fetchData(url: string): Promise<ApiResponse> {
const response = await fetch(url);
return await response.json();
}
function processUser(data: ApiResponse): Pick<User, 'id' | 'name'>[] {
return data.users.map(user => ({
id: user.id,
name: user.name,
}));
}
When You Legitimately Don't Know the Type
Use unknown instead of any:
// ✅ Use 'unknown' for truly dynamic data
function parseJSON(jsonString: string): unknown {
return JSON.parse(jsonString);
}
const data = parseJSON('{"name": "John"}');
// TypeScript forces you to check the type
if (typeof data === 'object' && data !== null && 'name' in data) {
console.log(data.name); // Type-safe access
}
// Or use type guards
interface User {
name: string;
}
function isUser(data: unknown): data is User {
return (
typeof data === 'object' &&
data !== null &&
'name' in data &&
typeof data.name === 'string'
);
}
if (isUser(data)) {
console.log(data.name); // TypeScript knows it's User
}
React Component Type Errors
AI tools generate React components with terrible TypeScript:
// ❌ Common AI-generated React component
function Button({ onClick, children, disabled }) {
// Parameters have implicit 'any' type
return (
<button onClick={onClick} disabled={disabled}>
{children}
</button>
);
}
The Proper React TypeScript Pattern
// ✅ Explicit prop types
interface ButtonProps {
onClick: () => void;
children: React.ReactNode;
disabled?: boolean;
variant?: 'primary' | 'secondary';
}
function Button({ onClick, children, disabled = false, variant = 'primary' }: ButtonProps) {
return (
<button
onClick={onClick}
disabled={disabled}
className={`btn btn-${variant}`}
>
{children}
</button>
);
}
// Or use React.FC (though it's less common now)
const Button: React.FC<ButtonProps> = ({ onClick, children, disabled, variant }) => {
// ...
};
useState Type Inference Issues
// ❌ AI generates this
const [data, setData] = useState(null); // type: null
// Later...
setData({ id: 1, name: 'John' }); // Error!
The Fix:
// ✅ Provide type parameter
interface UserData {
id: number;
name: string;
}
const [data, setData] = useState<UserData | null>(null);
// Now TypeScript understands
setData({ id: 1, name: 'John' }); // ✅
setData(null); // ✅
Third-Party Library Type Issues
AI tools often use libraries without proper type definitions:
// ❌ Library has no types
import someLibrary from 'some-library'; // Could not find declaration file
someLibrary.doSomething(); // 'any' type
Solutions
Option 1: Install type definitions
npm install --save-dev @types/some-library
Option 2: Create declaration file
// types/some-library.d.ts
declare module 'some-library' {
export function doSomething(value: string): void;
export default {
doSomething,
};
}
Option 3: Use type assertion (last resort)
import someLibrary from 'some-library';
const lib = someLibrary as {
doSomething: (value: string) => void;
};
lib.doSomething('test');
The Bolt.new TypeScript Loop
As mentioned in our build failures article, Bolt.new has a known issue (GitHub #5511) where the AI cannot fix TypeScript errors it creates. Users report asking the AI to fix the same type error 10+ times with no progress.
Breaking the Loop
- Copy the entire file into ChatGPT or Claude and ask for a fixed version
- Manually fix the error using the patterns in this article
- Disable strict checking temporarily (not recommended, but sometimes necessary)
- Start a new Bolt session with the corrected code
Gradual TypeScript Migration Strategy
If you inherited an AI-generated codebase with hundreds of type errors:
Step 1: Disable Strict Mode Temporarily
// tsconfig.json
{
"compilerOptions": {
"strict": false,
"noImplicitAny": false,
"strictNullChecks": false
}
}
Step 2: Fix Critical Errors
Focus on errors that cause runtime bugs:
- Null/undefined access
- Type mismatches in API calls
- Missing required properties
Step 3: Enable Rules Gradually
// Enable one at a time
{
"compilerOptions": {
"strict": false,
"noImplicitAny": true, // Start here
// Later: "strictNullChecks": true,
// Later: "strictFunctionTypes": true,
}
}
Step 4: File-by-File Approach
// @ts-check at top of file enables stricter checking
// @ts-ignore on specific lines to skip errors temporarily
// @ts-expect-error when you know something is wrong but acceptable
TypeScript Performance Issues
Large codebases with complex types can cause TypeScript to slow down or crash during builds:
// ❌ Overly complex types
type DeepNested = {
level1: {
level2: {
level3: {
level4: {
level5: string;
};
};
};
};
};
Optimization Tips
- Use type aliases instead of repeating complex types
- Avoid excessive type inference - be explicit
- Use
skipLibCheck: trueto skip checking node_modules - Upgrade TypeScript - newer versions are faster
When Type Errors Become Overwhelming
Sometimes you need expert help:
- 500+ type errors across the codebase
- Complex generic type issues you don't understand
- Third-party library conflicts
- Type errors that seem impossible to fix
- Circular type dependencies
Drowning in TypeScript errors? Book a hardening sprint and we'll make your codebase strictly typed and production-ready.