skip to Main Content

I have an Interface Person and I am able to create an object user1 of the type Person by assigning all the properties at once

export interface person {
  name: string;
  age: number;
  city: string;

}

let user1: person = {
    name:"ron",
    age: 22,
    city:"AL"
}

Is there a way for me to build this object instead of assigning all the properties at once. Im am looking for something like this

let user2:person;

user2.age = 22;
user2.name = "Dave";
user2.city = "NY"

3

Answers


  1. If you create a class that implements the interface you can set the default value of the properties to be empty

    class Class implements Person {
      name: string = "";
      age: number = 0;
      city: string = "";
    }
    

    and then set them as you want later

    Login or Signup to reply.
  2. One way around this is to declare an object with "empty" properties and then initialize them afterwards

    export interface person {
      name: string;
      age: number;
      city: string;
    
    }
    
    
    let user2:person = {
        name:"",
        age:-1,
        city:""
    };
    
    user2.age = 22;
    user2.name = "Dave";
    user2.city = "NY"
    
    Login or Signup to reply.
  3. You can use the type utility Partial<Type> when initializing the value to indicate that the properties have not yet been defined:

    let user: Partial<Person> = {};
    

    After initializing the property values, TypeScript will correctly infer that they do indeed exist:

    user.age = 22;
    user.name = "Dave";
    user.city = "NY";
    
    const doubleAge = user.age * 2; // Ok
    const lowercaseCity = user.city.toLowerCase(); // Ok
    const uppercaseName = user.name.toUpperCase(); // Ok
    

    TS Playground

    However, if you do not initialize one of the property values, TypeScript will emit an error diagnostic when trying to use it:

    let user: Partial<Person> = {};
    
    user.age = 22;
    
    const doubleAge = user.age * 2; // Ok
    
    const lowercaseCity = user.city.toLowerCase(); /* Error
                          ~~~~~~~~~
    'user.city' is possibly 'undefined'.(18048) */
    
    const uppercaseName = user.name.toUpperCase(); /* Error
                          ~~~~~~~~~
    'user.name' is possibly 'undefined'.(18048) */
    

    TS Playground

    There are still some scenarios where the inference isn’t enough — for example, when the value needs to be used as an argument to a function which requires a Person:

    declare function doSomethingWithPerson(person: Person): void;
    
    let user: Partial<Person> = {};
    
    user.age = 22;
    user.name = "Dave";
    user.city = "NY";
    
    doSomethingWithPerson(user); /* Error
                          ~~~~
    Argument of type 'Partial<Person>' is not assignable to parameter of type 'Person'.
      Property 'name' is optional in type 'Partial<Person>' but required in type 'Person'.(2345) */
    

    TS Playground

    In these cases, you can create a function called a type guard which will check at runtime to ensure that the type meets the stated expectations. A user-defined type guard is a function whose return type is a type predicate:

    function isPerson<T extends Record<PropertyKey, unknown>>(
      p: T,
    ): p is T & Person {
      return (
        typeof p.age === "number" &&
        typeof p.city === "string" &&
        typeof p.name === "string"
      );
    }
    

    See also in the handbook: generics

    Then you can check whether user actually meets the definition of Person before using it in order to avoid errors:

    let user: Partial<Person> = {};
    
    user.age = 22;
    user.name = "Dave";
    user.city = "NY";
    
    if (isPerson(user)) {
      doSomethingWithPerson(user); // Ok
    } else {
      // Handle the other case here
    }
    

    TS Playground

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search