This TypeScript compiler warning occurs when you declare a generic type parameter but don't reference it in the function signature, return type, or implementation. Fix it by using the parameter, removing it, or prefixing with underscore.
This error appears when TypeScript's `noUnusedParameters` or `@typescript-eslint/no-unused-vars` rule detects a generic type parameter that's declared but never actually used in your code. Type parameters exist to provide type safety and inference across your function or class, but when they're unused, they serve no purpose and can indicate a mistake or incomplete implementation. For example, declaring `function process<T>(value: string): void {}` triggers this error because `T` is declared but never referenced in the parameter types, return type, or function body. TypeScript flags this as it suggests either the type parameter was forgotten or shouldn't have been declared in the first place. This check helps catch phantom type parameters that were meant to be used but weren't, preventing subtle type safety bugs and keeping your codebase clean. The error became more prominent starting with TypeScript 2.5 when unused parameter detection was enhanced.
Look at the error message to see which type parameter is flagged as unused. Check your function, class, or interface declaration:
// Error: Type parameter 'T' is defined but never used
function processData<T>(id: number): void {
console.log(id);
}The type parameter T is declared but not referenced in the parameter list, return type, or function body.
Ask yourself: Does this function or class need to be generic? If the type parameter was meant to be used, add it to your signature:
// Fix: Use the type parameter
function processData<T>(data: T): T {
console.log(data);
return data;
}
// Or in the return type
function createArray<T>(): T[] {
return [];
}If you don't need it at all, the next step shows how to remove it.
If the generic isn't needed, simply remove it from the declaration:
// Before
function processData<T>(id: number): void {
console.log(id);
}
// After - no generic needed
function processData(id: number): void {
console.log(id);
}This is the cleanest solution when the type parameter serves no purpose.
For phantom type parameters that you need to keep for type-level reasons (like type branding or constraint enforcement), prefix the name with an underscore:
// Phantom type parameter for type branding
function createBranded<_Brand>(value: string): string & { __brand: _Brand } {
return value as string & { __brand: _Brand };
}
// Or when implementing an interface that requires the generic
interface Handler<T> {
handle(event: unknown): void;
}
// Implementation doesn't use T but must match interface
class MyHandler<_T> implements Handler<_T> {
handle(event: unknown): void {
console.log('handled');
}
}The underscore prefix tells TypeScript and ESLint to ignore this parameter.
If you have many intentionally unused type parameters, configure your ESLint rule to ignore them:
// .eslintrc.json
{
"rules": {
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
]
}
}This allows any parameter or variable starting with underscore to be unused without triggering errors.
For projects where this check is too strict, you can disable it in your TypeScript configuration:
// tsconfig.json
{
"compilerOptions": {
"noUnusedParameters": false,
"noUnusedLocals": false
}
}However, this is not recommended as it reduces type safety. Only use this as a last resort, and prefer using ESLint rules for more granular control.
Type Parameter Constraints and Defaults
You can add constraints or defaults to make unused type parameters more meaningful:
// With constraint - T still unused but provides compile-time check
function process<T extends string>(id: number): void {
console.log(id);
}
// With default - prevents need to specify type explicitly
function create<T = unknown>(): T[] {
return [];
}Phantom Types for Type Safety
Sometimes unused type parameters serve a purpose at the type level even if not used at runtime. This is called "type branding":
type UserId = string & { __brand: 'UserId' };
type ProductId = string & { __brand: 'ProductId' };
function createUserId<_Brand extends 'UserId'>(id: string): UserId {
return id as UserId;
}The _Brand parameter isn't used in the implementation but ensures type safety at compile time.
Interface and Class Merging
When merging interfaces with classes, type parameters may appear unused in one declaration but used in another:
interface Repository<T> {
find(id: string): T | null;
}
abstract class Repository<_T> {
protected cache: Map<string, unknown> = new Map();
}The underscore prefix on the class prevents the error while maintaining compatibility with the interface.
Type parameter 'X' is not used in the function signature
How to fix "Type parameter not used in function signature" in TypeScript
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript