How to fix Property 'x' is declared in class 'X' but its initializer or other property definition is missing in TypeScript

TypeScriptINTERMEDIATEMEDIUMUpdated Dec 11, 2025· 169 views

This TypeScript error occurs when strictPropertyInitialization is enabled and class properties are declared but not initialized. The fix involves initializing properties in the constructor, using definite assignment assertions, or adjusting compiler options.

Quick fix

Fixes TS2564

// BEFORE - Error
class User {
  name: string;  // Error: Property 'name' has no initializer
}

// AFTER - Fixed with initial value
class User {
  name: string = '';  // Initialize with empty string
  age: number = 0;    // Initialize with 0
  isActive: boolean = false;  // Initialize with false
  tags: string[] = [];  // Initialize with empty array
}

// For complex types, use appropriate defaults
class Config {
  settings: Record<string, any> = {};
  timeout: number = 5000;
  retries: number = 3;
}
  1. Initialize the property with a value
  2. Initialize properties in the constructor
  3. Use definite assignment assertion (!)
  4. Make properties optional with ?
typescript — error
// BEFORE - Error
class User {
name: string; // Error: Property 'name' has no initializer
}
// AFTER - Fixed with initial value
class User {
name: string = ''; // Initialize with empty string
age: number = 0; // Initialize with 0
isActive: boolean = false; // Initialize with false
tags: string[] = []; // Initialize with empty array
}
// For complex types, use appropriate defaults
class Config {
settings: Record<string, any> = {};
timeout: number = 5000;
retries: number = 3;
}
Property 'x' is declared in class 'X' but its initializer or other property definition is missing

What this error means

The TypeScript error "Property 'x' is declared in class 'X' but its initializer or other property definition is missing" (TS2564) occurs when you have the `strictPropertyInitialization` compiler option enabled (or `strict` mode which includes it) and you declare a class property without providing an initial value. This TypeScript safety feature ensures that class properties are properly initialized before use, preventing runtime errors where you might try to access `undefined` values. TypeScript needs to know that properties will have values when the class instance is created. The error appears because TypeScript cannot guarantee that the property will be assigned a value before it's accessed. This could lead to runtime errors in JavaScript where the property would be `undefined`. Common scenarios include: 1. Properties declared without initial values 2. Properties assigned only conditionally in the constructor 3. Properties that are meant to be initialized later via methods 4. Properties with complex initialization logic

Typical symptoms

  • Compilation fails with "Property is declared but its initializer or other property definition is missing"
  • Error code TS2564 appears in compiler output
  • IDE shows red underlines on class property declarations
  • Error occurs only when strictPropertyInitialization or strict mode is enabled
  • Properties declared without = value or constructor initialization
  • Code works in JavaScript but fails TypeScript compilation

Common causes

  1. strictPropertyInitialization compiler option is enabled (either directly or via strict: true)
  2. Class property declared without an initial value (e.g., name: string; instead of name: string = "default";)
  3. Property assigned only conditionally in constructor (if/else branches not covering all cases)
  4. Property initialized in a method called after constructor
  5. Abstract class properties without initialization in concrete subclasses
  6. Using ! definite assignment assertion incorrectly or forgetting it

How to fix "Property 'x' is declared in class 'X' but its initializer or other property definition is missing"

1Initialize the property with a value

The simplest fix is to provide an initial value when declaring the property:

typescript
// BEFORE - Error
class User {
  name: string;  // Error: Property 'name' has no initializer
}

// AFTER - Fixed with initial value
class User {
  name: string = '';  // Initialize with empty string
  age: number = 0;    // Initialize with 0
  isActive: boolean = false;  // Initialize with false
  tags: string[] = [];  // Initialize with empty array
}

// For complex types, use appropriate defaults
class Config {
  settings: Record<string, any> = {};
  timeout: number = 5000;
  retries: number = 3;
}

This ensures the property always has a value when the class is instantiated.

2Initialize properties in the constructor

If the initial value depends on constructor parameters or needs computation, initialize in the constructor:

typescript
// BEFORE - Error
class User {
  name: string;
  age: number;

  constructor(firstName: string, lastName: string, birthYear: number) {
    // Error: Properties not initialized
  }
}

// AFTER - Fixed in constructor
class User {
  name: string;
  age: number;

  constructor(firstName: string, lastName: string, birthYear: number) {
    this.name = `${firstName} ${lastName}`;
    this.age = new Date().getFullYear() - birthYear;
  }
}

// For optional parameters with defaults
class Product {
  name: string;
  price: number;
  discount: number;

  constructor(name: string, price: number, discount?: number) {
    this.name = name;
    this.price = price;
    this.discount = discount ?? 0;  // Use nullish coalescing for default
  }
}

Make sure all code paths in the constructor assign values to all properties.

3Use definite assignment assertion (!)

When you know a property will be initialized (but TypeScript can't verify it), use the definite assignment assertion (!):

typescript
// Use ! when you guarantee initialization
class Database {
  connection!: Connection;  // ! tells TypeScript "trust me, this will be initialized"

  async initialize() {
    this.connection = await createConnection();
  }
}

// For properties set by frameworks or dependency injection
class Controller {
  service!: Service;  // Injected by framework

  // Framework will set this property before use
}

// For lazy initialization
class Cache {
  data!: Map<string, any>;

  getData(): Map<string, any> {
    if (!this.data) {
      this.data = new Map();
    }
    return this.data;
  }
}

// WARNING: Only use ! when you're certain the property will be initialized
// before any access. Misuse can lead to runtime errors.

The ! operator tells TypeScript to skip the initialization check for that property.

4Make properties optional with ?

If a property can legitimately be undefined, mark it as optional:

typescript
// Use ? for properties that may be undefined
class UserProfile {
  name: string;
  avatarUrl?: string;  // Optional - may be undefined
  bio?: string;        // Optional - may be undefined

  constructor(name: string) {
    this.name = name;
    // avatarUrl and bio can remain undefined
  }
}

// Access optional properties safely
const profile = new UserProfile('Alice');
console.log(profile.avatarUrl?.toUpperCase());  // Optional chaining
console.log(profile.bio ?? 'No bio provided');  // Nullish coalescing

// Interface with optional properties
interface Config {
  requiredSetting: string;
  optionalSetting?: number;
  anotherOptional?: boolean;
}

// Class implementing interface
class AppConfig implements Config {
  requiredSetting: string;
  optionalSetting?: number;

  constructor(required: string) {
    this.requiredSetting = required;
  }
}

Optional properties (? syntax) explicitly tell TypeScript that undefined is a valid value.

5Adjust strictPropertyInitialization in tsconfig.json

If you need to disable this check (not recommended for new code), adjust your tsconfig.json:

json
// OPTION 1: Disable strictPropertyInitialization only
{
  "compilerOptions": {
    "strict": true,
    "strictPropertyInitialization": false  // Disable just this check
  }
}

// OPTION 2: Disable all strict checks (not recommended)
{
  "compilerOptions": {
    "strict": false  // Disables all strict checks including property initialization
  }
}

// OPTION 3: Use overrides for specific files (TypeScript 4.1+)
{
  "compilerOptions": {
    "strict": true
  },
  "files": [
    "src/strict-code.ts"
  ],
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "src/legacy/**/*"  // Legacy code without strict checks
  ]
}

Recommendation: Instead of disabling the check, fix the initialization issues. The check exists to prevent runtime errors.

If you have legacy code that can't be easily fixed, consider:
1. Creating a separate tsconfig for legacy code
2. Using // @ts-ignore comments sparingly
3. Gradually fixing properties over time

6Handle conditional initialization in constructor

When properties are initialized conditionally, ensure all code paths assign values:

typescript
// BEFORE - Error: Property may be undefined
class Auth {
  token: string;

  constructor(useToken: boolean) {
    if (useToken) {
      this.token = 'generated-token';
    }
    // Error: token not assigned when useToken is false
  }
}

// AFTER 1: Assign in all branches
class Auth {
  token: string;

  constructor(useToken: boolean) {
    if (useToken) {
      this.token = 'generated-token';
    } else {
      this.token = '';  // Assign default in else branch
    }
  }
}

// AFTER 2: Use ternary operator
class Auth {
  token: string;

  constructor(useToken: boolean) {
    this.token = useToken ? 'generated-token' : '';
  }
}

// AFTER 3: Initialize with default, then conditionally update
class Auth {
  token: string = '';  // Initialize with default

  constructor(useToken: boolean) {
    if (useToken) {
      this.token = 'generated-token';
    }
  }
}

// AFTER 4: Make property optional if it can be undefined
class Auth {
  token?: string;  // Mark as optional

  constructor(useToken: boolean) {
    if (useToken) {
      this.token = 'generated-token';
    }
  }
}

TypeScript analyzes all possible code paths in the constructor to ensure properties are initialized.

Advanced notes

### Understanding strictPropertyInitialization

The strictPropertyInitialization compiler option (enabled by strict: true) requires that:

1. Non-optional instance properties must be initialized:
- In their declaration: name: string = "default";
- In the constructor
- Via a definite assignment assertion (!)

2. Optional properties (?) are exempt from this requirement

3. Static properties are NOT checked by this rule

### Definite Assignment Assertions vs Non-null Assertions

Both use ! syntax but have different meanings:

typescript
// Definite assignment assertion - "I promise this will be initialized"
class Example1 {
  value!: string;  // TypeScript won't check initialization
}

// Non-null assertion - "This value won't be null/undefined"
class Example2 {
  getValue(): string | null {
    return Math.random() > 0.5 ? 'hello' : null;
  }

  useValue() {
    const val = this.getValue();
    console.log(val!.toUpperCase());  // ! says "val won't be null here"
  }
}

### Abstract Classes and Inheritance

Abstract classes have special rules:

typescript
abstract class Base {
  abstract requiredProp: string;  // Abstract - must be implemented
  optionalProp?: number;          // Optional in base class
  initializedProp: string = 'default';  // Has initializer
}

class Derived extends Base {
  requiredProp: string;  // Error: No initializer

  constructor() {
    super();
    this.requiredProp = 'value';  // Must initialize in constructor
  }
}

### Property Initialization Order

Properties are initialized in this order:
1. Property initializers (e.g., name: string = "default")
2. Constructor execution
3. Definite assignment assertions bypass the check entirely

### Framework-Specific Patterns

Angular/React/Vue components often use definite assignment assertions:

typescript
// Angular - properties injected by DI
@Component({...})
export class MyComponent {
  @Input() inputValue!: string;      // Set by parent component
  @ViewChild(ChildComp) child!: ChildComp;  // Set by framework

  ngOnInit() {
    // Safe to use inputValue and child here
  }
}

// React Class Component
class MyComponent extends React.Component<Props> {
  private timerId!: number;  // Set by setTimeout

  componentDidMount() {
    this.timerId = window.setTimeout(() => {}, 1000);
  }

  componentWillUnmount() {
    window.clearTimeout(this.timerId);
  }
}

### Migration Strategy for Legacy Code

When enabling strictPropertyInitialization in an existing codebase:

1. Start with `strictPropertyInitialization: false`
2. Enable for new files only using file-specific tsconfig overrides
3. Gradually fix properties starting with critical classes
4. Use a linter rule to track progress: "@typescript-eslint/strictPropertyInitialization": "error"

### Performance Considerations

Property initialization checks happen at compile time with no runtime cost. The ! operator also has no runtime effect - it's purely a TypeScript compile-time directive.

### Common Pitfalls

1. Forgotten else branches in conditional initialization
2. Async initialization that happens after constructor returns
3. Circular dependencies where Class A needs Class B which needs Class A
4. Framework lifecycle where properties are set after constructor but before use

For async initialization patterns:

typescript
class AsyncExample {
  private dataPromise: Promise<Data>;
  data!: Data;  // Will be set by the promise

  constructor() {
    this.dataPromise = this.loadData();
    this.dataPromise.then(result => {
      this.data = result;
    });
  }

  // Alternative: Don't store as property, use async method
  async getData(): Promise<Data> {
    return this.dataPromise;
  }
}

Frequently asked questions

What does "TS2564" mean?
The TypeScript error "Property 'x' is declared in class 'X' but its initializer or other property definition is missing" (TS2564) occurs when you have the strictPropertyInitialization compiler option enabled (or strict mode which includes it) and you declare a class property without providing an initial value. This TypeScript safety feature ensures that class properties are properly initialized before use, preventing runtime errors where you might try to access undefined values. TypeScript needs to know that properties will have values when the class instance is created.
How do I fix "TS2564"?
This TypeScript error occurs when strictPropertyInitialization is enabled and class properties are declared but not initialized. The fix involves initializing properties in the constructor, using definite assignment assertions, or adjusting compiler options.
What causes "TS2564"?
strictPropertyInitialization compiler option is enabled (either directly or via strict: true) Class property declared without an initial value (e.g., name: string; instead of name: string = "default";) Property assigned only conditionally in constructor (if/else branches not covering all cases)
Is the "TS2564" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading