简体   繁体   中英

TypeScript class declaration error with private variable

If I have a TypeScript class declaration like this:

export class myClass {
  constructor(public aVariable: number) {}
  private aPrivateVariable: number;
}

and then try to initialize it with:

let someVar: myClass[] = [{
  aVariable: 3
}, {
  aVariable: 2
}];

I get an error (at least in VS Code) saying:

Property 'aPrivateVariable' is missing in type '{ aVariable: number; }'.

Why can't I do this?

Thanks.

Imagine your class also has a method that uses this field:

 export class myClass {
  constructor(public aVariable: number) {}
  private aPrivateVariable: number;
  test(){  }
 }

Now if you would do the following:

 const instance: myClass = {
    aVariable: 1,
    test() {
      alert.aPrivateVariable + 1);
    }
 };

 instance.test();

It would fail. Therefore, you also need to add private properties.

 let someVar: myClass[] = [{
  aVariable: 3,
  aPrivateVariable: 2,
 }, {
  aVariable: 2,
  aPrivateVariable: 3
 }];

Type { aVariable: number; } { aVariable: number; } isn't compatible with myClass

As the manual states,

Private and protected members in a class affect their compatibility. When an instance of a class is checked for compatibility, if the target type contains a private member, then the source type must also contain a private member that originated from the same class. Likewise, the same applies for an instance with a protected member. This allows a class to be assignment compatible with its super class, but not with classes from a different inheritance hierarchy which otherwise have the same shape.

If myClass is supposed to be used as interface to assign plain objects that are structurally compatible with myClass class, separate interface should be provided:

interface IMyClass {
  aVariable: number;
}

export class myClass implements IMyClass {...}

let someVar: IMyClass[] = [{
  aVariable: 3
}];

and then try to initialize it

It should be noticed that the code above doesn't initialize the class. It's unclear what were the reasons to assign plain objects instead of class instances, but if someVar should contain instances of myClass , type error indicates the problem. Instances should be explicitly instantiated with new :

let someVar: myClass[] = [new myClass(3)];

Defining the objects in the way you did ( { aVariable: 2} ) does not instantiate them as myClass objects. This is a problem since aPrivateVariable is not being instantiated because myClass constructor is never called and the object you add does not match what myClass contains.

As this excerpt from the typescript handbook on type compatibility states :

Private and protected members in a class affect their compatibility. When an instance of a class is checked for compatibility, if the target type contains a private member, then the source type must also contain a private member that originated from the same class. Likewise, the same applies for an instance with a protected member. This allows a class to be assignment compatible with its super class, but not with classes from a different inheritance hierarchy which otherwise have the same shape.

One way to deal with this is to instantiate every object using something such as map()

const someVar: myClass[] = [2,3,1].map(num => myClass(num)) ;

Or, if you're confident of the shape of the object, you can use type coercion:

let someVar: myClass[] = [] as myClass[]

Be careful with this approach though since it does not guarantee that what's contained in the array matches the model of the class.

export class myClass {
   constructor(public aVariable: number) {}
   private aPrivateVariable: number;
}

The correct way would be really initializing your class like this:

const someVar: myClass[] = [
    new myClass(3),
    new myClass(2),
]

If you don't initialize your class then you want to get any methods from myClass , you will end up with object cast as myClass .

You forgot to declare the class. You can do it like this

const someVar: myClass[] = [new myClass(3), new myClass(2)];

Correct way to initialize this class is -

export class myClass {
  constructor(public aVariable: number) {}
  private aPrivateVariable: number;
}

let someVar: myClass = new myClass(3);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM