Robert Cooper
Robert Cooper

Reputation: 2230

TypeScript error regarding uninitialized variables in class constructor

TypeScript is complaining about an uninitialized class property, even though it appears to be properly assigned.

Here's a minimum reproducible example:

type Config = {
    color: string;
}

class Toto {
    color: string;

    constructor(config: Config) {
        this.setConfig(config);
    }

    setConfig(config: Config) {
        this.color = config.color;
    }
}

TypeScript playground

The compiler underlines the color property definition and throws the following error:

Property 'color' has no initializer and is not definitely assigned in the constructor.

The issue appears to be with using the setConfig method to set the value of color, since the following code produces no compiler errors:

type Config = {
    color: string;
}

class Toto {
    color: string;

    constructor(config: Config) {
        this.color = config.color;
    }
}

This problem is I want to be able to use the setConfig method to set class properties to different values during the lifetime of a class instance. I don't want to have to repeated the same code within both my constructor and setConfig method just to get around a TS compiler issue.

Does anyone know why the compiler can't see that the class variable is properly being set in the constructor?

Upvotes: 1

Views: 2605

Answers (3)

Robert Cooper
Robert Cooper

Reputation: 2230

TypeScript does not allow this since the setConfig method could be overwritten if even the Toto class is subclassed:

class SubToto extends Toto {
    setConfig() {
        // Do nothing
    }
}

Therefore, the two possible approaches are:

  1. Set the values directly in the constructor, and repeat the code within setConfig:
class Toto {
    color: string;

    constructor(config: Config) {
        this.color = config.color;
    }

    setConfig(config: Config) {
        this.color = config.color;
    }
}

This has the downside of repeating the code.

  1. Setting an initial empty value to the property.
class Toto {
    color: string | null = null;

    constructor(config: Config) {
        this.setConfig(config)
    }

    setConfig(config: Config) {
        this.color = config.color;
    }
}

This has the downside of having to now check if the property is empty before using it elsewhere in your class methods.

Upvotes: 1

apokryfos
apokryfos

Reputation: 40653

If you as the developer are certain that color will not go uninitialized in the constructor you can just tell the compiler that this is the case:

type Config = {
    color: string;
}

class Toto {
    color!: string;

    constructor(config: Config) {
        this.setConfig(config);
    }

    setConfig(config: Config) {
        this.color = config.color;
    }
}

The ! tells the compiler that this variable will not be null at the point when ! is used.

Of course in an ideal world the compiler would be able to detect the indirect setting but I don't think this is currently possible.

Playground Link

Upvotes: 3

mgm793
mgm793

Reputation: 2066

You can do it like this, because initially color is undefined. Or initialise it to empty string like private color: string = '';.

type Config = {
    color: string;
}

class Toto {

    private color: string|undefined;
    
    constructor(config: Config) {
        this.setConfig(config);
    }

    setConfig(config: Config) {
        this.color = config.color;
    }
}

Upvotes: 0

Related Questions