This TypeScript error occurs when trying to combine parameter properties (like public, private, readonly) with destructuring patterns in constructor parameters. Parameter properties provide shorthand syntax for declaring and initializing class members, but they cannot be used with object or array destructuring patterns.
TypeScript parameter properties are a convenient shorthand that allows you to declare and initialize class members directly from constructor parameters by adding modifiers like public, private, protected, or readonly. For example, `constructor(public name: string)` automatically creates a public `name` property. However, TypeScript does not support combining parameter properties with destructuring patterns (also called binding patterns). Destructuring allows you to extract values from objects or arrays directly in parameter lists, like `constructor({ firstName, lastName }: { firstName: string, lastName: string })`. The error "A parameter property cannot be declared using a binding pattern" occurs when you try to use both features together, such as `constructor(public { firstName, lastName }: { firstName: string, lastName: string })`. This syntax is not supported because it creates ambiguity in how the properties should be initialized and accessed.
Look for constructor parameters that combine modifiers with destructuring patterns:
// Problematic code - causes TS1187 error
class Person {
constructor(public { firstName, lastName }: { firstName: string, lastName: string }) {
// Error: A parameter property cannot be declared using a binding pattern
}
}The issue is the public modifier before the destructured object { firstName, lastName }.
Instead of trying to combine both features, handle them separately. Extract the destructured parameters first, then assign them to class properties:
// Solution 1: Separate destructuring and property assignment
class Person {
firstName: string;
lastName: string;
constructor({ firstName, lastName }: { firstName: string, lastName: string }) {
this.firstName = firstName;
this.lastName = lastName;
}
}This approach maintains the destructuring convenience while explicitly declaring and assigning properties.
If you don't need destructuring, use standard parameter properties with individual parameters:
// Solution 2: Traditional parameter properties
class Person {
constructor(
public firstName: string,
public lastName: string
) {}
}
// Usage
const person = new Person('John', 'Doe');This is the most straightforward approach when you have simple parameters.
For complex objects, define an interface and use it in the constructor:
// Solution 3: Interface with explicit property declaration
interface PersonData {
firstName: string;
lastName: string;
age?: number;
}
class Person {
firstName: string;
lastName: string;
age?: number;
constructor(data: PersonData) {
this.firstName = data.firstName;
this.lastName = data.lastName;
this.age = data.age;
}
}
// Usage with object literal
const person = new Person({ firstName: 'John', lastName: 'Doe', age: 30 });This approach provides type safety and clear structure for complex parameter objects.
For very complex initialization scenarios, consider alternative patterns:
// Solution 4: Factory method
class Person {
private constructor(
public firstName: string,
public lastName: string,
public age?: number
) {}
static create(data: { firstName: string; lastName: string; age?: number }): Person {
return new Person(data.firstName, data.lastName, data.age);
}
}
// Usage
const person = Person.create({ firstName: 'John', lastName: 'Doe', age: 30 });This pattern separates object construction from the class definition and can handle more complex initialization logic.
## Technical Background
Parameter properties and destructuring patterns are two distinct TypeScript features with different compilation requirements:
1. Parameter Properties: Compile to property declarations and assignments in the constructor
2. Destructuring Patterns: Compile to variable declarations and assignments from the parameter
Combining them creates ambiguity in the generated JavaScript. For example, what should constructor(public {x, y}) compile to? Should it create properties x and y on the instance, or just destructure into local variables?
## TypeScript Design Decision
The TypeScript team has considered this feature (see GitHub issue #5326) but hasn't implemented it due to semantic complexity. The main challenges include:
1. Property naming conflicts: How to handle cases where destructured variable names differ from desired property names
2. Access modifier application: Should modifiers apply to each destructured variable or the pattern as a whole?
3. Default values: How to combine parameter property modifiers with default values in destructuring
4. Nested patterns: How to handle deeply nested destructuring patterns
## Alternative Approaches in Other Languages
Some languages like C# support similar syntax with record types or primary constructors, but TypeScript's design constraints (compiling to JavaScript) make this more challenging to implement cleanly.
## Future Considerations
As TypeScript evolves, this feature might be added in future versions. Keep an eye on TypeScript release notes and the official GitHub repository for updates on this language feature request.
Type parameter 'X' is not used in the function signature
How to fix "Type parameter not used in function signature" in TypeScript
Type parameter 'X' is defined but never used
How to fix "Type parameter is defined but never used" 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