STRICT TYPING GUIDE - NO 'any' OR 'unknown' ALLOWED
Note: This is a legacy document. For current requirements, see Zero Tolerance Rules.
Table of Contents
- Core Principles
- Error Handling
- JSON Parsing
- Database JSON Fields
- External API Responses
- Function Parameters
- Catch Blocks
- Type Guards
- Platform-Specific Types
- AI Code Generation Guidelines
Core Principles
❌ NEVER USE
typescript
any
unknown
Record<string, any>
Record<string, unknown>✅ ALWAYS USE
typescript
// Define explicit interfaces
interface MyData {
field1: string;
field2: number;
}
// Or use Zod schemas with inferred types
const MyDataSchema = z.object({
field1: z.string(),
field2: z.number(),
});
type MyData = z.infer<typeof MyDataSchema>;Error Handling
❌ WRONG - Using 'unknown'
typescript
try {
await something();
} catch (error: unknown) { // FORBIDDEN
console.error(error);
}✅ CORRECT - Explicit Error Types
typescript
import { isError, isErrorResponse, getErrorMessage, type ErrorResponse } from '@/types/index.js';
try {
await something();
} catch (error: Error | ErrorResponse) { // Explicit union type
if (isError(error)) {
console.error(error.message);
logger.error(error.stack);
} else if (isErrorResponse(error)) {
console.error(error.message);
} else {
// TypeScript will catch this - error must be Error | ErrorResponse
}
}Define ErrorResponse Interface
typescript
// In src/types/errors.ts
export interface ErrorResponse {
message: string;
code?: string;
status?: number;
details?: ErrorDetails;
stack?: string;
}
export interface ErrorDetails {
field?: string;
constraint?: string;
value?: string | number;
}
// Type guards
export function isError(value: Error | ErrorResponse | object | string): value is Error {
return value instanceof Error;
}
export function isErrorResponse(value: Error | ErrorResponse | object | string): value is ErrorResponse {
return (
typeof value === 'object' &&
value !== null &&
'message' in value &&
typeof (value as ErrorResponse).message === 'string'
);
}
export function getErrorMessage(error: Error | ErrorResponse): string {
if (isError(error)) return error.message;
if (isErrorResponse(error)) return error.message;
return 'Unknown error';
}JSON Parsing
❌ WRONG - Using 'any' or 'unknown'
typescript
const data = JSON.parse(jsonString); // Returns 'any' - FORBIDDEN
const data: unknown = JSON.parse(jsonString); // FORBIDDEN✅ CORRECT - Parse with Explicit Type
typescript
import { parseJSON } from '@/types/index.js';
import { UserDataSchema, type UserData } from '@/types/user.js';
// Method 1: Using helper function with Zod
const data: UserData = parseJSON(jsonString, UserDataSchema);
// Method 2: Direct Zod parse
const rawData: string | number | boolean | object | null = JSON.parse(jsonString);
const data: UserData = UserDataSchema.parse(rawData);Define parseJSON Helper
typescript
// In src/utils/json.ts
import type { z } from 'zod';
export function parseJSON<T extends z.ZodType>(
json: string,
schema: T
): z.infer<T> {
try {
const parsed: string | number | boolean | object | null = JSON.parse(json);
return schema.parse(parsed);
} catch (error: Error | ErrorResponse) {
throw new Error(`JSON parsing failed: ${getErrorMessage(error)}`);
}
}Database JSON Fields
❌ WRONG - Casting to 'any'
typescript
const metrics = post.performanceMetrics as any; // FORBIDDEN
const context = post.generationContext as unknown; // FORBIDDEN✅ CORRECT - Explicit Type with Validation
typescript
import { validateJsonField } from '@/types/index.js';
import {
PerformanceMetricsSchema,
type PerformanceMetrics
} from '@/types/metrics.js';
// Method 1: Validate and get typed data
const metrics: PerformanceMetrics | null = validateJsonField(
post.performanceMetrics,
PerformanceMetricsSchema
);
if (metrics !== null) {
console.log(metrics.impressions); // Type-safe!
}
// Method 2: Direct Zod validation
const metrics: PerformanceMetrics = PerformanceMetricsSchema.parse(
post.performanceMetrics
);Define validateJsonField Helper
typescript
// In src/utils/validation.ts
import type { z } from 'zod';
export function validateJsonField<T extends z.ZodType>(
value: string | number | boolean | object | null | undefined,
schema: T
): z.infer<T> | null {
if (value === null || value === undefined) {
return null;
}
const result = schema.safeParse(value);
return result.success ? result.data : null;
}External API Responses
❌ WRONG - Using 'any' for API response
typescript
const response = await fetch(url);
const data: any = await response.json(); // FORBIDDEN✅ CORRECT - Define Platform Response Types
typescript
import { LinkedInAnalyticsSchema, type LinkedInAnalyticsResponse } from '@/types/platforms.js';
async function fetchLinkedInAnalytics(postId: string): Promise<LinkedInAnalyticsResponse> {
const response = await fetch(`https://api.linkedin.com/posts/${postId}/analytics`);
const rawData: string | number | boolean | object | null = await response.json();
// Validate the response
const data: LinkedInAnalyticsResponse = LinkedInAnalyticsSchema.parse(rawData);
return data;
}Define Platform Response Types
typescript
// In src/types/platforms.ts
import { z } from 'zod';
export const LinkedInAnalyticsSchema = z.object({
impressions: z.number().int().nonnegative(),
likes: z.number().int().nonnegative(),
comments: z.number().int().nonnegative(),
shares: z.number().int().nonnegative(),
engagement_rate: z.number().nonnegative(),
clicks: z.number().int().nonnegative().optional(),
});
export type LinkedInAnalyticsResponse = z.infer<typeof LinkedInAnalyticsSchema>;
// Do this for EVERY platform
export const TwitterAnalyticsSchema = z.object({
impressions: z.number().int().nonnegative(),
retweets: z.number().int().nonnegative(),
replies: z.number().int().nonnegative(),
likes: z.number().int().nonnegative(),
url_clicks: z.number().int().nonnegative().optional(),
});
export type TwitterAnalyticsResponse = z.infer<typeof TwitterAnalyticsSchema>;Function Parameters
❌ WRONG - Using 'any' for parameters
typescript
function processData(data: any): void { // FORBIDDEN
console.log(data.field);
}✅ CORRECT - Explicit Parameter Types
typescript
interface ProcessDataInput {
field: string;
value: number;
optional?: boolean;
}
function processData(data: ProcessDataInput): void {
console.log(data.field); // Type-safe!
}
// Or with Zod schema
const ProcessDataInputSchema = z.object({
field: z.string(),
value: z.number(),
optional: z.boolean().optional(),
});
type ProcessDataInput = z.infer<typeof ProcessDataInputSchema>;Catch Blocks
❌ WRONG - Using 'unknown' in catch
typescript
try {
await riskyOperation();
} catch (error: unknown) { // FORBIDDEN
// Can't do anything safely with unknown
}✅ CORRECT - Explicit Error Union Types
typescript
import { type ErrorResponse, isError, isErrorResponse, getErrorMessage } from '@/types/index.js';
try {
await riskyOperation();
} catch (error: Error | ErrorResponse) {
// Type guard to narrow the type
if (isError(error)) {
console.error(`Error: ${error.message}`);
logger.error(error.stack);
} else if (isErrorResponse(error)) {
console.error(`API Error ${error.code}: ${error.message}`);
logger.error(error.details);
}
// Or use helper
const message: string = getErrorMessage(error);
console.error(message);
}Type Guards
❌ WRONG - Checking 'unknown'
typescript
function isValidData(data: unknown): data is MyType { // FORBIDDEN
return typeof data === 'object';
}✅ CORRECT - Explicit Type Guards
typescript
interface MyType {
id: string;
name: string;
value: number;
}
function isMyType(
data: object | string | number | null | undefined
): data is MyType {
return (
typeof data === 'object' &&
data !== null &&
'id' in data &&
typeof (data as MyType).id === 'string' &&
'name' in data &&
typeof (data as MyType).name === 'string' &&
'value' in data &&
typeof (data as MyType).value === 'number'
);
}
// Usage
const data: object | string | number | null = getSomeData();
if (isMyType(data)) {
console.log(data.name); // Type-safe!
}
// Or better: use Zod
const result = MyTypeSchema.safeParse(data);
if (result.success) {
console.log(result.data.name); // Type-safe!
}Platform-Specific Types
Create Exhaustive Type Definitions
typescript
// src/types/platforms.ts
// LinkedIn
export interface LinkedInAnalyticsResponse {
impressions: number;
likes: number;
comments: number;
shares: number;
engagement_rate: number;
clicks?: number;
}
export const LinkedInAnalyticsSchema = z.object({
impressions: z.number().int().nonnegative(),
likes: z.number().int().nonnegative(),
comments: z.number().int().nonnegative(),
shares: z.number().int().nonnegative(),
engagement_rate: z.number().nonnegative(),
clicks: z.number().int().nonnegative().optional(),
});
// Twitter/X
export interface TwitterAnalyticsResponse {
impressions: number;
retweets: number;
replies: number;
likes: number;
url_clicks?: number;
}
export const TwitterAnalyticsSchema = z.object({
impressions: z.number().int().nonnegative(),
retweets: z.number().int().nonnegative(),
replies: z.number().int().nonnegative(),
likes: z.number().int().nonnegative(),
url_clicks: z.number().int().nonnegative().optional(),
});
// Facebook
export interface FacebookAnalyticsResponse {
impressions: number;
reactions: number;
comments: number;
shares: number;
clicks?: number;
}
// Instagram
export interface InstagramAnalyticsResponse {
impressions: number;
likes: number;
comments: number;
saves: number;
reach?: number;
}
// ... Define for ALL platformsAI Code Generation Guidelines
When using AI to generate code, ALWAYS follow these patterns:
Pattern 1: External API Call
typescript
// TEMPLATE for AI code generation
async function fetch{Platform}{Resource}(
accessToken: string,
resourceId: string
): Promise<{Platform}{Resource}Response> {
const response = await fetch(`https://api.{platform}.com/{endpoint}`);
if (!response.ok) {
throw new Error(`{Platform} API error: ${response.statusText}`);
}
const rawData: string | number | boolean | object | null = await response.json();
const data: {Platform}{Resource}Response = {Platform}{Resource}Schema.parse(rawData);
return data;
}Pattern 2: Database JSON Field Access
typescript
// TEMPLATE for AI code generation
import { validateJsonField } from '@/utils/validation.js';
import { {Type}Schema, type {Type} } from '@/types/{category}.js';
const field: {Type} | null = validateJsonField(
record.{fieldName},
{Type}Schema
);
if (field !== null) {
// Use field safely
console.log(field.property);
}Pattern 3: Error Handling
typescript
// TEMPLATE for AI code generation
import { type ErrorResponse, isError, getErrorMessage } from '@/types/index.js';
try {
await operation();
} catch (error: Error | ErrorResponse) {
if (isError(error)) {
logger.error(`Operation failed: ${error.message}`, {
stack: error.stack,
});
} else {
logger.error(`Operation failed: ${getErrorMessage(error)}`);
}
throw error;
}Pattern 4: API Route Handler
typescript
// TEMPLATE for AI code generation
import { z } from 'zod';
const RequestSchema = z.object({
field1: z.string(),
field2: z.number(),
});
type RequestType = z.infer<typeof RequestSchema>;
const ResponseSchema = z.object({
result: z.string(),
success: z.boolean(),
});
type ResponseType = z.infer<typeof ResponseSchema>;
export async function handler(
req: Request,
res: Response
): Promise<void> {
try {
// Validate input
const input: RequestType = RequestSchema.parse(req.body);
// Process
const result: string = await processRequest(input);
// Build response
const response: ResponseType = {
result,
success: true,
};
// Validate output (catches bugs)
const validatedResponse: ResponseType = ResponseSchema.parse(response);
res.json(validatedResponse);
} catch (error: Error | ErrorResponse | z.ZodError) {
if (error instanceof z.ZodError) {
res.status(400).json({
error: 'Validation failed',
details: error.format(),
});
} else {
res.status(500).json({
error: getErrorMessage(error),
});
}
}
}Checklist for ALL New Code
Before committing, verify:
- [ ] No
anytypes anywhere - [ ] No
unknowntypes anywhere - [ ] All function parameters have explicit types
- [ ] All function return types are explicit
- [ ] All catch blocks use
Error | ErrorResponse - [ ] All JSON.parse() calls use
parseJSON()helper - [ ] All Prisma JSON fields use
validateJsonField() - [ ] All external API responses have defined types
- [ ] All types have Zod schemas for validation
- [ ] Error handling uses type guards
Quick Reference
Instead of This ❌
typescript
any
unknown
Record<string, any>
as any
catch (error: unknown)
JSON.parse() // returns anyUse This ✅
typescript
interface MyType { ... }
type MyType = z.infer<typeof MyTypeSchema>
Record<string, string | number | boolean>
as MyType // with explicit type
catch (error: Error | ErrorResponse)
parseJSON(json, MyTypeSchema)Getting Help
- Check this guide first
- Look at existing code patterns in
src/types/ - All types should be in
src/types/{category}/ - All schemas should be colocated with types
- Ask in #engineering before using workarounds
REMEMBER: There is NO valid use case for any or unknown in this codebase.If you think you need it, you need to define a proper type instead.
Last Updated: January 2026Zero Tolerance for 'any' and 'unknown'