How to fix A required parameter cannot follow an optional parameter in TypeScript

TypeScriptINTERMEDIATEMEDIUMUpdated Dec 11, 2025· 107 views

This TypeScript error occurs when you place optional parameters (marked with ?) before required parameters in a function signature. TypeScript requires all optional parameters to come after all required parameters. The fix involves reordering parameters, using default values, or restructuring with object parameters.

Quick fix

Fixes TS1016

// ERROR: Optional before required
function processData(filter?: string, data: DataObject) {
  // ...
}

// FIXED: Required before optional
function processData(data: DataObject, filter?: string) {
  // ...
}

// ERROR in arrow function
const handler = (id?: number, name: string) => {
  // ...
};

// FIXED
const handler = (name: string, id?: number) => {
  // ...
};

// ERROR in class method
class UserService {
  getUser(id?: string, includeProfile: boolean) {
    // ...
  }
}

// FIXED
class UserService {
  getUser(includeProfile: boolean, id?: string) {
    // ...
  }
}
  1. Reorder parameters to put required ones first
  2. Use default parameter values instead of optional syntax
  3. Convert to object parameter for complex signatures
  4. Fix interface and type definitions
typescript — error
// ERROR: Optional before required
function processData(filter?: string, data: DataObject) {
// ...
}
// FIXED: Required before optional
function processData(data: DataObject, filter?: string) {
// ...
}
// ERROR in arrow function
const handler = (id?: number, name: string) => {
// ...
};
// FIXED
const handler = (name: string, id?: number) => {
// ...
};
// ERROR in class method
class UserService {
getUser(id?: string, includeProfile: boolean) {
// ...
}
}
// FIXED
class UserService {
getUser(includeProfile: boolean, id?: string) {
// ...
}
}
A required parameter cannot follow an optional parameter

What this error means

The "A required parameter cannot follow an optional parameter" error appears when TypeScript detects an invalid parameter order in a function or method declaration. In TypeScript, optional parameters (those marked with a question mark ?) must come after all required parameters in the parameter list. This rule exists because optional parameters can be omitted when calling the function, but TypeScript needs to know which parameters are being passed based on their position. If a required parameter comes after an optional one, TypeScript cannot determine whether a provided value is meant for the optional parameter (if omitted) or the required parameter. For example: ```typescript // ERROR: Required parameter 'b' follows optional parameter 'a?' function example(a?: string, b: string) { // ... } ``` When calling `example("hello")`, TypeScript doesn't know if "hello" should fill the optional `a` parameter (leaving `b` undefined) or if it should fill `b` (with `a` being undefined). This ambiguity is why the ordering rule exists.

Typical symptoms

  • Compilation fails with 'A required parameter cannot follow an optional parameter'
  • IDE shows red underlines on function/method declarations with mixed parameter types
  • Error appears when optional parameters (?) are placed before required parameters
  • Code fails to compile but may have worked in JavaScript
  • Error occurs in function declarations, arrow functions, and method definitions
  • TypeScript server reports parameter ordering violation

Common causes

  1. Placing optional parameters (marked with ?) before required parameters in function signatures
  2. Converting JavaScript code to TypeScript without adjusting parameter order
  3. Adding optional parameters to existing functions without reordering
  4. Mixing optional and required parameters in interface/type method definitions
  5. Incorrectly marking parameters as optional when they should be required
  6. Copy-pasting function signatures from different contexts without validation
  7. Using optional parameters in constructors or class methods with incorrect ordering

How to fix "A required parameter cannot follow an optional parameter"

1Reorder parameters to put required ones first

The simplest fix is to reorder your parameters so all required parameters come before any optional ones:

typescript
// ERROR: Optional before required
function processData(filter?: string, data: DataObject) {
  // ...
}

// FIXED: Required before optional
function processData(data: DataObject, filter?: string) {
  // ...
}

// ERROR in arrow function
const handler = (id?: number, name: string) => {
  // ...
};

// FIXED
const handler = (name: string, id?: number) => {
  // ...
};

// ERROR in class method
class UserService {
  getUser(id?: string, includeProfile: boolean) {
    // ...
  }
}

// FIXED
class UserService {
  getUser(includeProfile: boolean, id?: string) {
    // ...
  }
}

After reordering, update all function calls to match the new parameter order.

2Use default parameter values instead of optional syntax

If you need a parameter to have a default value but still be required in the signature, use default parameter syntax instead of optional syntax:

typescript
// ERROR: Optional before required
function calculate(a?: number, b: number, c: number) {
  // ...
}

// FIXED: Use default value instead of optional
function calculate(a: number = 0, b: number, c: number) {
  // ...
}

// Even better: Put required parameters first
function calculate(b: number, c: number, a: number = 0) {
  // ...
}

// With multiple optional parameters
function createUser(
  username: string,
  email: string = "",
  isAdmin: boolean = false,
  createdAt: Date = new Date()
) {
  // All required parameters come first
  // Optional parameters with defaults come last
}

Default parameters are still required in the type signature but get a default value if not provided. This maintains the required-before-optional rule.

3Convert to object parameter for complex signatures

For functions with many parameters or complex optional/required combinations, use an object parameter:

typescript
// ERROR: Complex mixed parameters
function search(
  query: string,
  limit?: number,
  offset: number,
  sortBy?: string,
  ascending: boolean
) {
  // ...
}

// FIXED: Use options object
interface SearchOptions {
  query: string;           // Required
  limit?: number;          // Optional
  offset: number;          // Required
  sortBy?: string;         // Optional
  ascending: boolean;      // Required
}

function search(options: SearchOptions) {
  const { query, limit = 10, offset, sortBy = "date", ascending } = options;
  // ...
}

// Cleaner usage
search({
  query: "typescript",
  offset: 0,
  ascending: true,
  // limit and sortBy are optional
});

// With destructuring in function signature
function search({
  query,
  limit = 10,
  offset,
  sortBy = "date",
  ascending
}: SearchOptions) {
  // ...
}

Object parameters provide better readability and flexibility for complex signatures.

4Fix interface and type definitions

The same rule applies to method signatures in interfaces and type aliases:

typescript
// ERROR in interface
interface DataProcessor {
  process(data: any, filter?: string, validate: boolean); // filter? before validate
}

// FIXED
interface DataProcessor {
  process(data: any, validate: boolean, filter?: string);
}

// ERROR in type alias
type Handler = (id?: string, payload: any) => void;

// FIXED
type Handler = (payload: any, id?: string) => void;

// ERROR in generic function type
type Transformer<T> = (input?: T, options: TransformOptions) => T;

// FIXED
type Transformer<T> = (options: TransformOptions, input?: T) => T;

Check all interface, type, and class definitions for proper parameter ordering.

5Use function overloads for multiple signatures

If you need different parameter combinations, use function overloads:

typescript
// Function with overloads
function configure(config: string): void;
function configure(config: string, options: ConfigOptions): void;
function configure(config: string, options?: ConfigOptions): void {
  // Implementation handles both cases
  if (options) {
    // With options
  } else {
    // Without options
  }
}

// Usage
configure("production");
configure("development", { debug: true });

// Another example with different types
function parse(input: string): ParsedResult;
function parse(input: string, strict: boolean): ParsedResult;
function parse(input: string, strict?: boolean): ParsedResult {
  // Implementation
  return { /* ... */ };
}

Overloads let you define multiple call signatures while keeping a single implementation with proper optional/required ordering.

6Check and update all function calls

After fixing parameter order, update all function calls:

typescript
// Original (error)
function process(userId?: string, data: UserData) {
  // ...
}

// Calls that need updating
process("user123", userData);      // userId = "user123", data = userData
process(undefined, userData);      // userId = undefined, data = userData

// Fixed function
function process(data: UserData, userId?: string) {
  // ...
}

// Updated calls (swap arguments)
process(userData, "user123");      // data = userData, userId = "user123"
process(userData);                 // data = userData, userId = undefined

// Use a linter to find all call sites
// In VS Code: Search for function name
// Or use: grep -r "process(" src/

Use your IDE's find references feature to locate all call sites and update them systematically.

Advanced notes

### TypeScript's Parameter Ordering Rules

TypeScript enforces strict parameter ordering for type safety and predictable behavior:

1. Required parameters first: All parameters without ? or default values
2. Optional parameters last: Parameters marked with ?
3. Default parameters: Can appear anywhere but behave like required parameters in the type system
4. Rest parameters: Always last: (...args: any[])

### Why This Rule Exists

The ordering requirement prevents ambiguity in function calls. Consider:

// Hypothetical (invalid) TypeScript
function ambiguous(a?: string, b: string) {
console.log(a, b);
}

// If this were allowed, what should happen?
ambiguous("hello");
// Is a = "hello", b = undefined? ❌
// Or a = undefined, b = "hello"? ❌

TypeScript chooses safety over flexibility here. Other languages handle this differently:

- JavaScript: No compile-time checking; runtime errors if required params are undefined
- Python: Allows keyword arguments to skip optional params: func(b="hello")
- C#: Named arguments solve this: Func(b: "hello")

### Workarounds and Alternatives

1. Tuple types for positional flexibility:
type Params = [string, string?] | [string?, string]; // Not allowed either

2. Currying for partial application:
const createUser = (username: string) => (email?: string) => (isAdmin?: boolean) => {
// ...
};

3. Builder pattern for complex construction:
class QueryBuilder {
private query: string;

setQuery(q: string) {
this.query = q;
return this;
}

setLimit(limit?: number) {
// ...
return this;
}
}

### Migration from JavaScript

When converting JavaScript to TypeScript, watch for these patterns:

// JavaScript pattern that needs fixing
function jsStyle(a, b, c) {
if (c === undefined) {
// c is optional in practice
}
}

// TypeScript version needs explicit optional/required
function tsStyle(a: string, b: string, c?: string) {
// ...
}

### Strict Mode Implications

With strict: true in tsconfig.json, TypeScript is stricter about parameter types. Consider enabling strict mode gradually:

{
"compilerOptions": {
"strict": true,
// Or enable individually:
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true
}
}

### Tooling Support

- ESLint: @typescript-eslint rules can catch parameter ordering issues
- Prettier: Won't fix but will format consistently
- VS Code: Quick fixes can reorder parameters or add defaults
- tsc --noEmit: Check without building to catch parameter issues early

### Performance Considerations

Parameter ordering doesn't affect runtime performance but improves:
- Compiler speed (fewer ambiguous cases to analyze)
- Developer experience (clearer error messages)
- Code maintenance (predictable function signatures)

Remember: TypeScript's goal is to catch errors at compile time. This parameter ordering rule, while sometimes inconvenient, prevents a class of runtime errors related to incorrect argument passing.

Frequently asked questions

What does "TS1016" mean?
The "A required parameter cannot follow an optional parameter" error appears when TypeScript detects an invalid parameter order in a function or method declaration. ) must come after all required parameters in the parameter list. This rule exists because optional parameters can be omitted when calling the function, but TypeScript needs to know which parameters are being passed based on their position.
How do I fix "TS1016"?
This TypeScript error occurs when you place optional parameters (marked with ?) before required parameters in a function signature. TypeScript requires all optional parameters to come after all required parameters. The fix involves reordering parameters, using default values, or restructuring with object parameters.
What causes "TS1016"?
Placing optional parameters (marked with ?) before required parameters in function signatures Converting JavaScript code to TypeScript without adjusting parameter order Adding optional parameters to existing functions without reordering
Is the "TS1016" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading