| name | rule-typescript |
| description | TypeScript conventions — strict mode, type patterns, and inference preferences |
Rule typescript
Apply this rule whenever work touches:
TypeScript conventions for the schemas package
This is a published npm library where type safety directly impacts every consumer. Strict TypeScript configuration is non-negotiable.
Strict mode
The tsconfig extends @tsconfig/recommended and enables strict: true, which covers all strict family checks (strictNullChecks, strictFunctionTypes, strictBindCallApply, etc.).
No any — ever
In a schema library, any undermines the entire value proposition. Every any is a hole in the type system that propagates to consumers.
export function parseSchema(data: any): any {
return SomeSchema.parse(data);
}
export function parseSchema(data: unknown): MassIDData {
return MassIDDataSchema.parse(data);
}
When working with truly dynamic data, use unknown and narrow:
const result = response.data as MassIDData;
const result = MassIDDataSchema.parse(response.data);
Explicit return types for exports
Every exported function must declare its return type. This serves as documentation and prevents accidental API changes.
export function createFixture() {
return { name: 'test', weight_kg: 100 };
}
export function createFixture(): MassIDData {
return { name: 'test', weight_kg: 100 };
}
Internal (non-exported) functions should prefer inference to reduce noise:
function buildMetadata(input: RawInput) {
return { title: input.name, created_at: new Date().toISOString() };
}
Zod for runtime validation
Never write manual type guards when Zod can validate. The schemas ARE the source of truth — use them.
function isMassIDData(data: unknown): data is MassIDData {
return typeof data === 'object' && data !== null && 'name' in data;
}
const result = MassIDDataSchema.safeParse(data);
if (result.success) {
}
Interface vs type
Use interface for object shapes that may be extended by consumers or composed with other interfaces. Use type for unions, intersections, mapped types, and Zod inferences.
interface SchemaMetadata {
title: string;
description: string;
}
type MassIDData = z.infer<typeof MassIDDataSchema>;
type SchemaResult = MassIDData | CertificateData;
Imports
This project does not use path aliases. Use relative imports:
import { UuidSchema } from '../../../shared/schemas/primitives/ids.schema';
Type assertions
Avoid as assertions. If you must assert, prefer satisfies for compile-time checking without widening:
const config = { timeout: 5000 } as Config;
const config = { timeout: 5000 } satisfies Config;
The only acceptable as usage is as const for literal types and narrowing from unknown after validation.
@ts-ignore and @ts-expect-error
Never use @ts-ignore. If you must suppress an error, use @ts-expect-error with a comment explaining why:
const result = legacyFunction();
const result = legacyFunction();
If you find yourself needing @ts-expect-error, consider fixing the root cause first.