Home > database >  Variables not resolving to members in interface method
Variables not resolving to members in interface method

Time:10-19

I have an array of IDoctor and I get error:

error TS2304: Cannot find name 'firstName'

...when I execute console.log(testUser[0].getFullName()).

I want to print firstName and lastName from the object.

export interface IPerson {
  id: number;
  firstName: string;
  lastName: string;
  getFullName: () => string;
  gender: Gender;
}

export interface IDoctor extends IPerson {
  doctorNo: number;
}

const testUser: IDoctor[] = [
    {
    id: 1,
    firstName: "a",
    lastName: "aa",
    getFullName: () =>  `Doctor First & Last Name: ${firstName} ${lastName}`,
    gender: Gender.Male,
    doctorNo: 1
  },
  {
    id: 2,
    firstName: "b",
    lastName: "bb",
    getFullName: () => `Doctor First & Last Name: ${firstName} ${lastName}`,
    gender: Gender.Female,
    doctorNo: 2
  }
];  

console.log("First Doctor",testUser[0].getFullName());

CodePudding user response:

You can't use firstName/lastName like that, you're referencing variable that do not exist.

You might want to create a class Person & Doctor and then use this:

getFullName: () => `Doctor First & Last Name: ${this.firstName} ${this.lastName}`,

CodePudding user response:

As implied by MatthieuRiegler's answer, you have to tell where firstName and lastName come from, otherwise the TS/JS engine will look for these variables in scope (and find out that they do not exist in any parent scope, hence the error message).

With this keyword, we now specify that they come from the calling context. If using a class (as suggested by MatthieuRiegler's answer), that context is the class instance.

But it is very possible to achieve this without using classes yet. But we have to use normal methods (functions), instead of arrow functions, which do not have their own context:

Arrow functions don't have their own bindings to this [...], and should not be used as methods.

(hence the new error message when trying to use arrow functions with this as methods: instead of referring to the object, it refers to the outer class, your EmployeeComponent)

Such methods can very well use this to refer to the object (which will be the calling context), without resorting to classes:

const testUser: IDoctor[] = [
    {
        id: 1,
        firstName: "a",
        lastName: "aa",
        // Use a normal function as method; `this` refers to the calling context
        getFullName() {
            return `Doctor First & Last Name: ${this.firstName} ${this.lastName}`;
        },
        gender: Gender.Male,
        doctorNo: 1
    }
];

console.log(
    "First Doctor",
    // The calling context is what comes before the dot (.)
    // so `testUser[0]` here
    testUser[0].getFullName()
);
// [LOG]: "First Doctor",  "Doctor First & Last Name: a aa" 

Since the getFullName method will be used in every IDoctor, and provided that the body is the same for all of them, it is possible to factorize it:

function getFullName(this: IPerson) {
    return `Doctor First & Last Name: ${this.firstName} ${this.lastName}`
}

In that case, we have to tell explicitly to TypeScript what this will represent: https://www.typescriptlang.org/docs/handbook/2/functions.html#declaring-this-in-a-function

Then we can use it in every object:

const testUser: IDoctor[] = [
    {
        id: 2,
        firstName: "b",
        lastName: "bb",
        getFullName, // Use the factorized function
        gender: Gender.Female,
        doctorNo: 2
    }
];

Playground Link

  • Related