2

I have this code stackblitz

export class Student {
  id: number;
  name: string;
  age?:number;

  get studentType():string {
    return 'fullTime'
  }

  constructor(params: Student) {
    Object.assign(this, params);
  }
}

const student = new Student({id:1, name: 'Jon'}); //ts error here

I get the below error

Argument of type '{ id: number; name: string; }' is not assignable to parameter of type 'Student'. Property 'studentType' is missing in type '{ id: number; name: string; }'.

While studentType is a get only property and can't bet set.

What is the reason for that and how can I solve it?

ps. (I don't want to make it nullable like studentType? or convert it to just a function)

4 Answers 4

1

Getters / Setters are exactly like regular properties, thats why Typescript can't distinguish between a getter / setter and a regular property. You could make all properties optional though, with that you can omit the studentType:

  constructor(params: Partial<Student>) {
     Object.assign(this, params);
  }

However other properties (e.g. name) could also be omitted now. To make that more typesafe you could introduce an additional interface:

export interface StudentData {
  id: number;
  name: string;
  age?:number;
}

export class Student implements StudentData {
  get studentType():string {
    return 'fullTime'
  }

  constructor(params: StudentData) {
     Object.assign(this, params);
   }
 }
Sign up to request clarification or add additional context in comments.

Comments

1

That is a more controversial topic in TypeScript. For class, TypeScript consider the overall shape of the class to be the type.

This includes private variables and methods, and in this case, including the getter/setter.

One solution to your problem is you can use Partial<>

constructor(params: Partial<Student>) { ... }

or Pick<>

constructor(params: Pick<Student, 'id' | 'name' | 'age'>) { ... }

Another way is to create an interface yourself:

interface IStudent { id: number, name: string, age?:number }
class Student implements IStudent {
  constructor(params: IStudent) { ... }
}

3 Comments

by using Partial name can be omitted
Yes it can. Or you can use Pick<> too. Which gives you more control.
I meant it shouldn't be omitted
1

What is the reason for that?

Basically, {id:1, name: 'Jon'} is not a student, since that object lacks a studentType property. This seems obvious and idiotic but makes sense, since typescript cannot know wether you're gonna rely on that property of the argument or not.

In your constructor, you just call Object.assign and let it go. But you could be calling some function that actually relies on the argument having that property, which could led to a runtime error if not pointed out by typescript.

and how can I solve it?

Well, there are several answers already. I would just type the constructor parameter properly. If you expect an object that has id, name and/or age I would type it accordingly:


export class Student {
  id: number;
  name: string;
  age?:number;

  get studentType():string {
    return 'fullTime'
  }

  constructor(params: {id: number, name: string, age?: number}) {
    Object.assign(this, params);
  }
}

const student = new Student({id:1, name: 'Jon'}); //ts error here

Comments

0

This is because you are giving the type in constructor as Student. This can be done:

export class Student {
  id: number;
  name: string;
  age?: number;

constructor(id:number, name:string,age?:number) {
    this.age = age;
    this.name = name;
    this.id = id;
}

  get studentType():string {
    return 'fullTime'
  }

}

const student = new Student(1, 'Jon');

2 Comments

I need to create the object by passing {id:1, name: 'Jon'}
Then you can create a separate class/interface for Student Data or pass a any type.constructor(studObj:any) { this.age = studObj.age; this.name = studObj.name; this.id = studObj.id; }

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.