简体   繁体   中英

Typescript casting always returns “object”

Lets say I have two interfaces which have two the same members id, and name:

export interface InterfaceA {
    id: number;
    name: string;
    //some other members
}

export interface InterfaceB {
    id: number;
    name: string;
    //some other members
}

I would like to get collection of elements of both types to populate some combobox. I need id, name and type of every element, so I've made following class

export class AssignableDevice {
    id: number;
    name: string;
    type: string;

    constructor(device: InterfaceA | InterfaceB) {
        this.id = device.id;
        this.name = device.name;
        this.type = typeof device; //still returns "object"
    }
}

// in onInit method : 

ngOnInit() {
    super.ngOnInit();

    this.dataService.getInterfaceA().subscribe((data) => {
      data.forEach((element) => this.devices.push(new AssignableDevice(element as InterfaceA)));
    });

    this.dataService.getInterfaceB().subscribe((data) => {
      data.forEach((element) => this.devices.push(new AssignableDevice(element as InterfaceB)));
    })
}

But problem is I always get "object" in "AssignableDevice" class constructor, and I have no idea why is this happening. I can achieve my goal by using some enum, but I wonder, why this solution is not working, and how could achieve this. I'd rather not make any changes in InterfaceA or InterfaceB.

You can't access the TypeScript type of an object at runtime (in the general case). TypeScript provides a compile-time type system. The typeof that you're using is the JavaScript runtime typeof , which always returns "object" for objects of any kind (and for null ).

You've said you want to send the type to the backend, so you definitely need it at runtime. I can see at least two ways to do that:

  1. You could define your interfaces as branded interfaces to ensure that you always include the type:

     export interface InterfaceA { id: number; name: string; //some other members type: "InterfaceA"; // <== This is a _string literal type_ whose only valid value is the string "InterfaceA" } export interface InterfaceB { id: number; name: string; //some other members type: "InterfaceB"; // <=== String literal type }

    Now any object you assign to a variable, property, or parameter of type InterfaceA has to have a type property with the string "InterfaceA" and similar for InterfaceB . Then your code would use that type property.

  2. You could make your constructor private, and only allow creation via createX methods for the interfaces:

     export class AssignableDevice { id: number; name: string; type: string; private constructor(device: InterfaceA | InterfaceB, type: string) { this.id = device.id; this.name = device.name; this.type = type; } static createA(device: InterfaceA): AssignableDevice { return new AssignableDevice(device, "InterfaceA"); } static createB(device: InterfaceB): AssignableDevice { return new AssignableDevice(device, "InterfaceB"); } }

    Now you use the appropriate createX method for the type of the object you have. Since you make that choice when writing the code, TypeScript can typecheck to see that you're passing the right type of object to createX .

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