tru7
tru7

Reputation: 7212

typescript optional property with a getter

This is a simplified example:

class PersonParms{
    name:string;
    lastName:string;
    age?:number;
    get fullName(){return this.name + " " + this.lastName;}
}

class Person{
    constructor(prms:PersonParms){
    }
}

new Person({name:'John',lastName:'Doe'})  // ts error: Property 'fullName' is missing in type '{ name: string; lastName: string; }'.

The idea is to pass a literal object as the intizalizer of PersonParms but having that getter you can neither declare the getter optional or add the property to the object literal. Is there another way to achieve it?

Upvotes: 17

Views: 16473

Answers (10)

Harlen Alvarez
Harlen Alvarez

Reputation: 1

If you don't want to make every property optional using Partial, you can just omit the getters.

class PersonParms{
        name:string;
        lastName:string;
        age?:number;
        get fullName(){return this.name + " " + this.lastName;}
    }
    
    class Person{
        constructor(prms: Omit<PersonParms, 'fullName'> ){
        }
    }
    
    new Person({name:'John',lastName:'Doe'})

Upvotes: 0

Ezward
Ezward

Reputation: 17702

Remember that optional is a type concept. A getter is an implementation. The implementation can return an optional type. In a class that implements an interface with an optional readonly property, the class may leave off the getter. See this answer get and set in TypeScript

Upvotes: 1

mtsuggs
mtsuggs

Reputation: 91

If you cast the object this will prevent the compile time error.

export class IndividualModel {
    constructor(individual: IndividualModel = null) {
        if (individual) {
            this.individualKey = individual.individualKey;
            this.firstName = individual.firstName;
            this.lastName = individual.lastName;
        }
    }

    individualKey: string;
    firstName?: string;
    lastName?: string;
    get fullName(): string {
        return `${this.lastName}, ${this.firstName}`;
    }
}
const individual = new IndividualModel(<IndividualModel>{ individualKey: 'some-key' });

Upvotes: 0

Santiago M. Quintero
Santiago M. Quintero

Reputation: 1273

As of April 2020, there is NO way to implement this.

There is an inconclusive PR for this: https://github.com/microsoft/TypeScript/pull/16344

A proposed solution via an interface is presented here: https://github.com/microsoft/TypeScript/pull/16344

Personally, the solution did not meet my needs, and I rather declared the property as private.

Hopefully, we can have better luck in the future.

Upvotes: 6

distante
distante

Reputation: 7005

If you creates a new instance of PersonParms then the error will be gone.

class PersonParms{
    name:string;
    lastName:string;
    age?:number;
    get fullName(){return this.name + " "+this.lastName;}
}

class Person{
    constructor(prms:PersonParms){
    }
}

const personParams = new PersonParms();
personParams.name = 'John';
personParams.lastName = 'John';
new Person(personParams)  // No error because this is an instance of PersonParams

I am not sure where/how do you use PersonParms.fullname but in your case I would use this:

interface PersonParms{
    name:string;
    lastName:string;
    age?:number;    
}

class Person implements PersonParms{
    name: string;
    lastName: string;
    age?:number
    constructor(prms: PersonParms) {
        this.name = prms.name;
        this.lastName = prms.lastName;
        this.age = prms.age;
    }

    get fullName(){return this.name + " "+this.lastName;}
}

const person = new Person({ name: 'John', lastName: 'Doe' });

console.log(person.fullName); // John Doe

Upvotes: 1

Bogdan
Bogdan

Reputation: 696

I found this solution which is ok for me:

class Person {
  name?:string;
  lastName?:string;
  age?: number;
  fullName?:string;

  constructor(public config: { name: string, lastName: string }) {
    Object.defineProperty(this,'fullName',{
           get(){return this.name + " " + this.lastName;}
          });

}

Upvotes: 2

Akshay
Akshay

Reputation: 52

   class PersonParms {
      name: string;
      lastName: string;
      age?: number;

     getFullName?(): string | null { return this.name + ' ' + this.lastName; }
  }

  class Person {
     constructor(prms: PersonParms) {
     }
  }
 new Person({ name: 'John', lastName: 'Doe' });

Upvotes: -3

Akshay
Akshay

Reputation: 52

class PersonParms {
  name: string;
  lastName: string;
  age?: number;
  fullName?: string = this.name + ' ' + this.lastName;
}

class Person {
  constructor(prms: PersonParms) {
  }
}

new Person({ name: 'John', lastName: 'Doe' });

Upvotes: 0

Pavel
Pavel

Reputation: 2554

Very interesting. I think, you should report an issue to TypeScript, because methods can be optional (see below), but property getters not. It is strange.. As a workaround I can suggest two variants. A nice one:

class PersonParms {
    name:string;
    lastName:string;
    age?: number;

    getFullName?() {return this.name + " "+this.lastName;}
}

And a second one, that is hacky, because there we make all the properties optional when passing to constructor.

class PersonParms {
    name:string;
    lastName:string;
    age?: number;

    get fullName(){return this.name + " "+this.lastName;}
}

class Person{
    constructor(prms: Partial<PersonParms>){
    }
}

Upvotes: 13

basarat
basarat

Reputation: 275847

Is there another way to achieve it?

Here is how I would do it:

class Person {
  constructor(public config: { name: string, lastName: string }) {}
  age?: number;
  get fullName() { return this.config.name + " " + this.config.lastName; }
}

new Person({ name: 'John', lastName: 'Doe' }) 

Upvotes: 2

Related Questions