Never cast types unless absolutely necessary. This includes:
- Manual generic type parameters (e.g.,
<Type>) - Type assertions using
as - Type assertions using
satisfies
Infer types by going up the logical chain:
- Schema validation as source of truth (Convex, Zod, etc.)
- Type inference from function return types, API responses
- Fix at source (schema, API definition, function signature) rather than casting at point of use
// Bad
const result = api.getData() as MyType
const value = getValue<MyType>()
// Good
const result = api.getData() // Type inferred from return type
const value = getValue() // Type inferred from implementationAll generic type parameters must be prefixed with T.
// Bad
function withCapability<Args extends unknown[], R>(
handler: (user: AuthUser, ...args: Args) => R,
) { ... }
// Good
function withCapability<TArgs extends unknown[], TReturn>(
handler: (user: AuthUser, ...args: TArgs) => TReturn,
) { ... }Common names: T, TArgs, TReturn, TData, TError, TKey, TValue