When Typecasted in Typescript, the result is consistently returned as "object"

Consider a scenario where there are two interfaces with identical members 'id' and 'name':

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

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

The goal is to gather elements from both types to populate a combobox with their id, name, and type. For this purpose, a class is created as shown below:

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; //always 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)));
    })
}

However, the issue arises where the type in the constructor always resolves to "object" and the reason behind this behavior remains unclear. One possible workaround involves using an enum, but the focus is on understanding why the current solution is not functioning as expected without altering InterfaceA or InterfaceB.

Answer №1

At runtime, accessing the TypeScript type of an object is not possible in the general case. TypeScript offers a compile-time type system. The typeof you are utilizing refers to the JavaScript runtime typeof, which consistently returns "object" for objects of any kind (including null).

If you need to send the type to the backend, there are a couple of methods you can consider:

  1. You can define your interfaces as branded interfaces to ensure inclusion of the type:

    export interface InterfaceA {
        id: number;
        name: string;
        //other properties
        type: "InterfaceA"; // **String literal type** with the only valid value being the string "InterfaceA"
    }
    
    export interface InterfaceB {
        id: number;
        name: string;
        //other properties
        type: "InterfaceB"; // **String literal type**
    }
    

    Now, any object assigned to a variable, property, or parameter of type InterfaceA must have a type property with the string "InterfaceA" (and similar for

    InterfaceB</code). Your code will then utilize this <code>type
    property.

  2. You can make your constructor private and only allow creation through 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 must use the appropriate createX method based on the object type you have. By making this choice during coding, TypeScript can ensure you are passing the correct type of object to createX.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to locate the Sass file corresponding to a specific HTML page in Ionic?

According to the Ionic guide at Ionic Framework Tutorial The instructions suggest adding the styles in the Sass file for the respective page. I'm having trouble locating the Sass file for the HTML pages within the template folder. ...

Identifying Classifications Based on Input Parameters

I'm encountering some difficulty in typing a function that calls an external API and returns data based on the parameters sent. Here is what I have so far... import axios from 'axios'; interface IGetContactArgs { properties?: string[]; } ...

Using JavaScript to place a particular tag at a designated position

I have a string that looks like this: var txtstr='<p>Text 1</p><p>&nbsp;</p><p>Text &nbsp;2</p><p>&nbsp;</p><p>Text 3&nbsp;</p>'; I have an <img src=..../> tag and ...

How to selectively make properties optional in Typescript conditions

Currently, I am working on creating a utility type to unwrap nested monads of Options in my code. Here is the progress I have made so far: export interface Option<T> { type: symbol; isSome(): boolean; isNone(): boolean; match<U>(fn: Mat ...

The issue arises when Jest ceases to function properly once the "type": "module" is configured in the tsconfig.json file

I have encountered an issue while using jest for unit testing in typescript. When I set "type": "module" in the tsconfig.json file, my app runs perfectly fine but jest stops working and displays a "ReferenceError: require is not defined". const { pathsToMo ...

When exporting a custom ES6 module and importing it into a different local project, you may encounter unexpected outputs such as being undefined or

Currently, I am using TypeScript 3.4.5 and Webpack 4.32.2 on Windows 10 via WSL. My goal is to create a local package of tools that consolidates basic classes into an index file for exporting. However, when I try to import these classes into other project ...

Can a standard tuple be matched with its corresponding key?

This code snippet showcases a function that can recognize that the key "banana" cannot have the value "red": type Fruits = { banana: 'yellow' | 'green' strawberry: 'red' } const fruit = <K extends keyof Fruits>(modu ...

Typescript: Assigning Variables Without Prior Declaration

In my upcoming Node.js application, I decided to use TypeScript for development. However, I encountered a perplexing issue while working on the code below: class AuthService { public async init(req: Request, res: Response) { let user: IUser | ...

Angular2 - How to track or listen for (click) events on dynamically inserted HTML elements

I'm trying to inject a string with a dynamically retrieved (click) event into an Angular2 template. Since this string is fetched from the back-end after the DOM is loaded, Angular doesn't recognize the injected event. Here's an example of t ...

Is there a way to incorporate new members into a pre-existing type in TypeScript?

While examining the definition file for the commander project, one can observe the following interface being utilized: interface IExportedCommand extends ICommand { Command: commander.ICommandStatic; Option: commander.IOptionStatic; [key: stri ...

Ways to manage drag and drop functionality within Cypress when traditional Cypress techniques are not effective

I need help with the drag and drop function in Cypress. I have tried three different methods but none of them seem to work. I have included my code below, which is not functioning as expected. Does anyone have any suggestions on what might work better in t ...

Angular2 checkboxes for filtering data

I'm working with an Angular2 grid that showcases an array of Fabrics, each with its own color or fabric type properties. Right now, all Fabrics are displayed in the grid, but I need to implement a series of checkboxes for color and fabric type, along ...

If the user clicks outside of the navigation menu, the menu is intended to close automatically, but unfortunately it

I have a nav file and a contextnav file. I've added code to the nav file to close the navigation when clicking outside of it, but it's not working. How can I ensure that the open navigation closes when clicking outside of it? Both files are in ts ...

The function Event.target.value is coming back as null

I've been working on creating a timer window, and I've set up a separate component for it. However, I'm facing an issue with passing the time from the main component to the child component. The problem lies in the fact that the state of the ...

The layout of the RadDataForm with nested groups in a GridLayout using NativeScript Angular does not properly display all fields on iOS

In the Angular NativeScript (6.3.0) component, I am facing an issue with XML where the form group expands and shrinks correctly on Android when the group title is tapped. However, on iOS, the group does not expand when using GridLayout rows="auto" and doe ...

The error "Property 'push' does not exist on type '() => void'" occurs with Angular2 and Typescript arrays

What is the method to initialize an empty array in TypeScript? array: any[]; //To add an item to the array when there is a change updateArray(){ this.array.push('item'); } Error TS2339: Property 'push' does not exist on type &a ...

Steps to deactivate two choices in a multi-select dropdown menu and visually dim those options

Hey there, I recently worked with Angular8 and Bootstrap 4. I utilized a Bootstrap multi-select dropdown, where I encountered an issue: specifically, I'm trying to disable and gray out the options for PL Marketing and CL Marketing but have been unsucc ...

Creation of source map for Ionic 2 TypeScript not successful

Struggling with debugging my Ionic 2 application and in need of guidance on how to include souceMap for each typescript file that corresponds to the javascript files. Despite enabling "sourceMap":true in my tsconfig.json file, the dev tools in Chrome do n ...

Is it possible to nullify an object and utilize nullish coalescing for handling potentially undefined constants?

In my development work with React, I often utilize a props object structured like this: const props: { id: number, name?: string} = { id: 1 }; // 'name' property not defined const { id, name } = props; // the 'name' constant is now fore ...

What is preventing the CKEditor 4 Angular module from properly validating form fields?

Why is it that the form field validation for the CKEditor 4 Angular module does not seem to be functioning properly? You can find my code here. I have experimented with different combinations of .touched, .pristine, and .valid. Despite this, the CKEdito ...