TS2564Strict Mode
Since TS 2.7

Fix TS2564: Property Has No Initializer

Learn why TypeScript throws TS2564 for uninitialized class properties under strictPropertyInitialization, and how to properly initialize them.

error TS2564: Property 'x' has no initializer and is not definitely assigned in the constructor

What This Error Means

TS2564 fires when you declare a class property with a type annotation but don't give it a value — either at the declaration site or inside the constructor. TypeScript's strictPropertyInitialization check (part of strict mode) wants to guarantee that every property has a value before anyone tries to read it.

Without this check, accessing an uninitialized property would silently return undefined, even if the type says it should be a string or number. TS2564 prevents that entire category of bugs.

// The general shape of the error:
// Property 'email' has no initializer and is not definitely assigned in the constructor.

Common Causes

1. Declaring Properties Without Default Values

The most straightforward case — you declared a property but forgot to initialize it.

// ❌ Broken
class UserService {
  baseUrl: string
  //~~~~~~ Error: Property 'baseUrl' has no initializer
  //       and is not definitely assigned in the constructor.
  timeout: number
  //~~~~~~~ Same error
 
  async fetchUser(id: string) {
    return fetch(`${this.baseUrl}/users/${id}`)
  }
}
// ✅ Fixed — provide default values
class UserService {
  baseUrl: string = "https://api.example.com"
  timeout: number = 5000
 
  async fetchUser(id: string) {
    return fetch(`${this.baseUrl}/users/${id}`)
  }
}

2. Initializing Properties Outside the Constructor

TypeScript's analysis only looks at the constructor for initialization. If you set properties in a separate method called from the constructor, TypeScript can't verify it.

// ❌ Broken
class DatabaseConnection {
  host: string
  port: number
  //   ~~~~~~ Error: Property 'port' has no initializer
 
  constructor(config: { host: string; port: number }) {
    this.initialize(config) // TypeScript can't see into this call
  }
 
  private initialize(config: { host: string; port: number }) {
    this.host = config.host
    this.port = config.port
  }
}
// ✅ Fixed — initialize directly in the constructor
class DatabaseConnection {
  host: string
  port: number
 
  constructor(config: { host: string; port: number }) {
    this.host = config.host
    this.port = config.port
  }
}

3. Properties Set by a Framework Lifecycle Hook

Frameworks like Angular or decorators in libraries like TypeORM set properties outside the constructor, which TypeScript can't track.

// ❌ Broken
class UserComponent {
  userId: string
  //~~~~~ Error: Property 'userId' has no initializer
 
  // Angular sets this via @Input() before ngOnInit
  ngOnInit() {
    this.loadUser(this.userId)
  }
 
  loadUser(id: string) { /* ... */ }
}
// ✅ Fixed — use the definite assignment assertion (appropriate here)
class UserComponent {
  userId!: string // '!' tells TypeScript: "I guarantee this will be set"
 
  ngOnInit() {
    this.loadUser(this.userId)
  }
 
  loadUser(id: string) { /* ... */ }
}

How to Fix It

  1. Assign a default value at the declaration. This is the safest and most readable approach:

    class Config {
      retries: number = 3
      verbose: boolean = false
    }
  2. Initialize in the constructor. If the value depends on constructor arguments, assign it there:

    class Config {
      retries: number
      constructor(retries: number) {
        this.retries = retries
      }
    }
  3. Make the property optional. If the property genuinely might not have a value, add ?:

    class SearchFilter {
      query?: string // undefined until the user types something
    }
  4. Use the definite assignment assertion (!) as a last resort. This tells TypeScript you guarantee the property will be assigned before it's read. Only use this when a framework or external code handles initialization:

    class Widget {
      element!: HTMLElement // set by the framework after construction
    }
  5. Don't disable strictPropertyInitialization. Turning off this check in tsconfig.json silences the error everywhere, which defeats the purpose of using strict mode.

FAQ

What causes TS2564?

TS2564 is triggered by the strictPropertyInitialization compiler option (enabled by default when strict is true). It checks that every class property declared with a type annotation is assigned a value either at the declaration or inside the constructor. If TypeScript can't prove the property will have a value by the time the constructor finishes, it raises this error.

How do I fix property has no initializer?

The best fix depends on your situation. If there's a sensible default, assign it directly (count: number = 0). If the value comes from outside, take it as a constructor parameter. If the property is truly optional, add a ? to the declaration. Only use the ! assertion when you're certain an external mechanism (like a framework) will assign the value before it's read.

Should I use the definite assignment assertion?

The ! modifier (name!: string) is a promise to the compiler that you'll handle initialization yourself. It's appropriate for framework-managed properties (Angular's @Input(), TypeORM's @Column()) where the framework guarantees assignment. It's inappropriate as a shortcut to silence the error when you simply forgot to initialize something — in that case, you're hiding a real bug.

Share this reference

Stay Updated

Get the latest TypeScript tips, tutorials, and course updates delivered straight to your inbox.

No spam, unsubscribe at any time.