An API that returns Promise<any> for network requests or data operations forces every TypeScript consumer to cast results manually — const users = await client.get('/users') as User[]. This eliminates compile-time type checking at exactly the boundary where runtime errors are most common. ISO 25010 modifiability suffers because any change to the response shape goes undetected until runtime. The consumer cannot trust the type system to catch contract mismatches between their models and your API's actual output.
Low because the impact is limited to TypeScript consumers and does not cause runtime failures — the type ergonomics are poor but the functionality remains intact.
Add generic type parameters to data-handling methods so consumers can specify their expected response types.
// Before — returns any:
export class Client {
async request(path: string): Promise<any> { /* ... */ }
}
// After — generic return type:
export class Client {
async request<T>(path: string): Promise<T> { /* ... */ }
}
// Consumer gets full type safety:
const users = await client.request<User[]>('/api/users')
// ^? User[]
For event emitters, use a typed event map: on<K extends keyof Events>(event: K, handler: (data: Events[K]) => void). At least 50% of data-handling APIs should use generics before this check passes.
ID: sdk-package-quality.api-surface.type-generics
Severity: low
What to look for: Count all public API functions that handle generic data. For each, examine the TypeScript types in the public API for places where generics would improve the consumer experience:
any or unknown instead of generic Tclient.get('/users') returns Promise<any> instead of Promise<T> where the consumer can specify client.get<User[]>('/users').Pass criteria: The public API uses generics where they would benefit consumers — particularly for response types, collection operations, and event handling. The consumer can specify types for their use case rather than casting from any — at least 50% of data-handling APIs should use TypeScript generics for type safety. Report: "X generic-capable APIs found, Y use TypeScript generics."
Fail criteria: The public API uses any or untyped returns for operations where generics would be natural (API responses, data transformations, event payloads). Consumers must cast results to get type safety.
Skip (N/A) when: The package is written in plain JavaScript with no TypeScript. Also skip if the package's API has no natural generic points — every function takes and returns concrete types (e.g., a date formatting library). Skip for Go (uses different generics pattern), Rust (check for appropriate use of generics in the public API).
Detail on fail: Quote the actual return type showing the missing generic. Example: "The client.request() method returns Promise<any>. Consumers must cast: const users = await client.request('/users') as User[]. Add a generic: client.request<User[]>('/users') for type-safe responses."
Remediation: Generics let consumers supply their own types, getting type safety without your package needing to know their data structures.
// Before — returns any:
export class Client {
async request(path: string): Promise<any> { /* ... */ }
}
// After — generic return type:
export class Client {
async request<T>(path: string): Promise<T> { /* ... */ }
}
// Consumer gets type safety:
const users = await client.request<User[]>('/api/users')
// ^? User[]