This TypeScript error occurs when you define a function with optional parameters followed by required parameters, which violates TypeScript's parameter ordering rules. Optional parameters must come after all required parameters in a function signature. The error helps maintain consistent and predictable function signatures throughout your codebase.
This TypeScript compiler error occurs when you declare a function or method with an optional parameter (denoted by a question mark `?`) that is followed by a required parameter. In TypeScript, all optional parameters must be placed at the end of the parameter list, after all required parameters. This rule ensures that when calling a function, you can omit optional parameters without needing to provide placeholder values for them. The error prevents ambiguous function signatures where it would be unclear which parameters are being passed when some are omitted. This is a fundamental rule in TypeScript's type system that maintains consistency with JavaScript's handling of optional arguments and prevents runtime errors from incorrect parameter binding.
Look at the error message to find which function has the incorrect parameter order. The error will point to the specific line where a required parameter follows an optional one.
// ERROR: Required parameter cannot follow optional parameter
function greet(name?: string, greeting: string): void {
// name is optional, greeting is required - WRONG ORDER
console.log(`${greeting}, ${name || "Guest"}!`);
}Rearrange the parameters so all optional parameters (marked with ?) come after all required parameters. This is the fundamental fix for this error.
// CORRECT: Optional parameters come after required ones
function greet(greeting: string, name?: string): void {
// greeting is required, name is optional - CORRECT ORDER
console.log(`${greeting}, ${name || "Guest"}!`);
}
// Now you can call it correctly:
greet("Hello"); // Works: name is optional
greet("Hello", "John"); // Also worksInstead of using the ? syntax for optional parameters, consider using default parameter values. This often makes the intent clearer and follows the same ordering rules.
// Using default values instead of optional syntax
function greet(greeting: string, name: string = "Guest"): void {
console.log(`${greeting}, ${name}!`);
}
// Both calls work:
greet("Hello"); // Uses default "Guest"
greet("Hello", "John"); // Uses provided name
// This also works with multiple optional parameters:
function createUser(
username: string, // required
email: string = "", // optional with default
isAdmin: boolean = false // optional with default
) {
// ...
}The same rule applies to method declarations in classes, interfaces, and type aliases. Ensure all optional parameters come last in these contexts too.
interface UserService {
// ERROR: Optional before required
findUsers(filter?: string, limit: number): User[];
}
interface UserService {
// CORRECT: Required before optional
findUsers(limit: number, filter?: string): User[];
}
class UserRepository {
// ERROR in class method
save(user?: User, validate: boolean): void {}
// CORRECT
save(validate: boolean, user?: User): void {}
}Function type declarations and callback signatures must also follow the optional parameter ordering rule.
// Function type declaration
type GreetFunction = (name?: string, greeting: string) => void; // ERROR
type GreetFunction = (greeting: string, name?: string) => void; // CORRECT
// Callback parameter
type Callback = (error?: Error, data: any) => void; // Common Node.js pattern - ERROR!
// Node.js callback pattern should use:
type Callback = (error: Error | null, data?: any) => void; // CORRECT
// OR
type Callback = (error: Error | null | undefined, data: any) => void; // Also worksIf you have many optional parameters or complex requirements, consider using a parameter object instead. This avoids ordering issues entirely.
// Instead of many optional parameters:
function createUser(
username: string,
email?: string,
age?: number,
isAdmin?: boolean,
createdAt?: Date
) {
// Hard to manage, error-prone
}
// Use a parameter object:
interface UserOptions {
username: string;
email?: string;
age?: number;
isAdmin?: boolean;
createdAt?: Date;
}
function createUser(options: UserOptions) {
// All options are accessible via options.property
// No ordering issues
}
// Clean usage:
createUser({
username: "john_doe",
email: "[email protected]",
isAdmin: true
});If using function overloads, ensure each overload signature follows the optional parameter rule. Overloads must be consistent in their parameter ordering.
// ERROR: Overload with incorrect ordering
function process(input: string, validate?: boolean): string;
function process(input: number, validate?: boolean): number;
function process(input: string | number, validate?: boolean) {
// Implementation
}
// Actually this is CORRECT since optional is last
// But if you had:
function process(validate?: boolean, input: string): string; // ERROR in overload
function process(validate?: boolean, input: number): number; // ERROR in overload
function process(validate: boolean, input: string | number) {
// Implementation would be wrong
}If you need a variable number of arguments, consider using rest parameters (...args) instead of multiple optional parameters. Rest parameters must always come last.
// Instead of many optional parameters:
function join(
separator?: string,
...items: string[] // ERROR: rest parameter must be last
): string {
return items.join(separator);
}
// CORRECT: Required first, then optional, then rest
function join(
items: string[], // required
separator: string = ",", // optional with default
...extraOptions: any[] // rest parameter last
): string {
return items.join(separator);
}The "required parameter cannot follow optional parameter" rule exists because of how JavaScript handles function arguments. When you call a function with fewer arguments than parameters, JavaScript fills them from left to right. If optional parameters could come before required ones, you'd need to pass undefined explicitly for the optional parameter to reach the required one, which defeats the purpose of optional parameters. TypeScript's rule aligns with common JavaScript patterns and prevents confusing APIs. However, there are exceptions: in constructor overloads for classes, you might see patterns that appear to violate this rule, but they're actually different constructor signatures. Also, when using tuple types in rest parameters, the ordering rules can be more complex. For callback patterns (like Node.js error-first callbacks), the convention is (error: Error | null, data?: T) => void, which places the required error parameter first, then optional data. Some developers use union types like Error | null | undefined for the first parameter to make it effectively optional while technically being required. Understanding this rule helps design cleaner, more predictable APIs that are easier to use correctly.
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
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript