TypeScript Language Patterns
Priority: P0 (Critical)
Implementation Guidelines
- Type annotations: Explicit params and return types; infer locals.
- Interfaces vs types:
interfacefor object shapes and APIs;typefor unions, intersections, and aliases. - Strict mode: Use
strict: true. Null safety: optional chaining?.and nullish coalescing??. - Enums: Prefer literal unions or
as const; avoid runtimeenum. - Generics: Use for reusable, type-safe code.
- Type guards: Use
typeof,instanceof, or user-defined type predicates. - Utility types: Use
Partial,Pick,Omit,Recordand custom utilities as needed. - Immutability: Prefer
readonlyarrays/objects; use const assertionsas constandsatisfies. - Template literal types: Use for patterns like
on${Capitalize<T>}. - Discriminated unions: Use a literal
kind(or similar) property to discriminate. - Advanced: Mapped, conditional, and indexed access types when appropriate.
- Access: Default
public; useprivate/protectedor#privatewhen needed. - Branded types: Use for nominal typing, e.g.
string & { __brand: 'Id' }.
Anti-Patterns
- No
any: Useunknownor specific types; neverany. - No
Function: Use concrete signatures, e.g.() => void. - No runtime
enum: Use union types oras constto avoid runtime cost. - No non-null assertion
!: Use proper narrowing instead. - No lint disables: Do not use
eslint-disableorts-ignore; fix issues properly.
Testing Patterns
- Mock types: Use
jest.Mocked<T>oras unknown as T; neverany. - Enums: Use enum values (e.g.
AppointmentStatus.UPCOMING) not string literals where the type is an enum. - DTOs: Ensure test data includes all required fields expected by DTOs.
- Repository mocks: Mock every repository method used by the code under test (
findOne,create,save,findAndCount,createQueryBuilder, etc.).
Common Test Issues
| Problem | Solution |
|---|---|
| Service method name mismatch | Check implementation and mock the methods actually called. |
| Error message mismatch | Use exact messages from shared constants (e.g. ErrorMessages). |
| Mock missing required properties | Provide full mocks or use as unknown as Type for complex cases. |
CurrentUser incomplete in mocks |
Include all required fields (id, email, subscriptionTier, createdAt, updatedAt). |
| Auth/guard mocks failing | Provide complete service mocks (e.g. logger, userRepository) or cast via unknown. |
| Wrong controller params | Match decorators (e.g. @CurrentUserDecorator()) and pass the correct types. |
Quick Reference
// Branded type
type UserId = string & { __brand: "Id" };
// satisfies: validate shape and infer
const cfg = { port: 3000 } satisfies Record<string, number>;
// Discriminated union
type Result<T> = { kind: "ok"; data: T } | { kind: "err"; error: Error };
Additional Resources
For advanced type patterns and utility types, see reference.md.
Source: cuonglph11/mini-chris — distributed by TomeVault.