Unable to retrieve a property from a variable with various data types

In my implementation, I have created a versatile type that can be either of another type or an interface, allowing me to utilize it in functions.

type Value = string | number
interface IUser { name: string, id: string }
export type IGlobalUser = Value | IUser;

When I require a function parameter to be of type IGlobalUser, I naturally expect to access the properties of the interface IUser. For example:

foo(user: IGlobalUser) { alert(user.name) } 

Unfortunately, TypeScript throws an error:

Property 'name' does not exist on type 'string | number | IUser'.   
Property 'name' does not exist on type 'string'.

I am aiming for the function to accept both Value and IUser seamlessly. Any suggestions on how to make this happen?

Answer №1

To determine whether a variable is of a certain type, you can utilize User-Defined Type Guards.

type Value = string | number
interface IUser { name: string, id: string }
export type IGlobalUser = Value | IUser;

function isUser(checkObj: IGlobalUser): checkObj is IUser {
  const optionalUser = checkObj as IUser;
  
  return isObject(optionalUser) && 
    optionalUser.id !== undefined && 
    optionalUser.name !== undefined;
}

function foo(user: IGlobalUser) {

  if (isUser(user)) {
    alert(user.name);
  }
} 

function isObject(obj: any) {
  return obj !== null && typeof obj === 'object';
}

The function isUser takes in a parameter of type IGlobalUser, and checks if it's an IUser. This allows for runtime type checking.

While this translates to regular JavaScript, TypeScript recognizes the function's role in determining types. Using the user defined guard function informs TypeScript about the variable's type.

Within VS Code:

Upon conversion to JavaScript, the code will include the isUser function and corresponding conditional statements. Including a check like this within your codebase is beneficial regardless. Defining it through a Type Guard ensures both runtime validation and enhanced TypeScript feedback based on the identified scenarios.

Answer №2

The function is designed to handle both Value and IUser. TypeScript is alerting you that it's unable to determine whether the type of user is a string, number, or IUser, and in the first two scenarios, user doesn't contain the property name.

To resolve this issue, apply a typeof type guard to distinguish between the cases so that the compiler stops generating complaints:

type Value = string | number
interface IUser { name: string, id: string }
type IGlobalUser = Value | IUser;

function bar(user: IGlobalUser) { 
    if (typeof user === 'object') {
        console.log(`IUser: ${user.name}`);
    } else {
        console.log(`string or number: ${user}`);
    }
} 

bar({ name: 'John Doe', id: '42'});
bar('Jane Doe');
bar(43);

Try it out here online.

Answer №3

Using JavaScript solution is more efficient in terms of runtime performance

foo(user: IrGlobalUser) {
  alert((typeof user === 'object') && user.name)
} 

On the other hand, TypeScript solution only works during compile time

foo(user: IrGlobalUser) {
  alert((user as IUser).name)
} 

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

Having difficulty grasping the significance of the data received from the API response

Currently, as I am working on my personal Portfolio for a Web Developer course, I have encountered an issue with correctly implementing my API to retrieve information from the database. Previously, I faced no problem when using a .json file, but now, I am ...

Interfaces and Accessor Methods

Here is my code snippet: interface ICar { brand():string; brand(brand:string):void; } class Car implements ICar { private _brand: string; get brand():string { return this._brand; } set brand(brand:string) { this. ...

Stop committing changes in Git when there are any TypeScript errors found

While working on my project in TypeScript using Visual Code, I encountered a situation where I was able to commit and push my changes to the server through Git (Azure) even though there was an error in my code causing a build failure. It made me wonder i ...

Struggling with fetching the email value in .ts file from ngForm in Angular?

I'm trying to retrieve the form value in my .ts file, but I am only getting the password value and not the email. Here is the code snippet: <div class="wrapper"> <form autocomplete="off" class="form-signin" method="post" (ngSubmit)="lo ...

Cannot proceed with module import: Type 'ModuleWithProviders<T>' must have a single type argument

ERROR in node_modules/@angular/fire/firestore/firestore.module.d.ts:7:74 - error TS2314: Generic type 'ModuleWithProviders<T>' requires 1 type argument(s). 7 static enablePersistence(persistenceSettings?: PersistenceSettings): ...

Component re-rendering and initializing useReducer

I made some revisions to this post. Initially, I shared the entire problem with my architecture and later updated it to focus directly on the issue at hand in order to make it easier for the community to provide assistance. You can now jump straight to the ...

Tips for validating email addresses and enforcing minimum length requirements

In order to validate email input for the correct format and ensure minimum length validations for first name and password, I am looking to utilize only bootstrap. While I have successfully implemented required field validations for the inputs, I am unsure ...

I am working on an Angular application that includes a dynamic form for an attendance system for employees. I am currently trying to figure out how to generate the JSON data

I have a dynamic form in my reactive attendance system for employees. When I click on submit, I need to generate JSON data like the following: { "user_id": "1", "branch_id": "4", "auth_token": "59a2a9337afb07255257199b03ed6076", "date": "2019- ...

What is the best way to represent a state with two possible fields in React using TypeScript?

There is a specific state item that can have its own value or reference another item using an ID. interface Item { itemName: string; itemValue: { valLiteral: number } | { idNumber: string }; } const indItem1: Item = { itemName: "first sample&quo ...

Create a union type by utilizing indices of an array type

For instance: type BasicTheme = { name: 'basic'; colors: [string, string]; }; type AdvancedTheme = { name: 'advanced'; colors: [string, string, string, string]; }; type MainColor = ???; // 'main-1' | 'main-2&apo ...

The repository's dependencies remain unresolved by Nest

I encountered an error in my nestjs application. Unfortunately, I am having trouble identifying the issue within my code snippet. Here is a glimpse of the relevant sections: AppModule import { Module } from '@nestjs/common'; import { TypeOrmMod ...

Detecting if a string is in sentence or title case with a typeguard

When setting the sameSite property of a cookie, it must be either Strict, Lax, or None. However, the package I'm using uses lowercase values for this attribute. Therefore, I need to adjust the first letter of the string: let sentenceCaseSameSite: &quo ...

substitute one item with a different item

I am facing an issue with updating the address object within an organization object. I receive values from a form that I want to use to update the address object. However, when I try to change the address object in the organization using Object.assign, i ...

custom field component for react-hook-form

I have been working on creating a form field component that can be utilized at both the root form level and as a nested field. export type FirstNameField = { firstName: string; }; type GenericFormType<T, NS extends string | never = never> = NS ext ...

Utilize rest parameters for destructuring操作

I am attempting to destructure a React context using rest parameters within a custom hook. Let's say I have an array of enums and I only want to return the ones passed into the hook. Here is my interface for the context type enum ConfigItem { Some ...

Unsynchronized state of affairs in the context of Angular navigation

Within my Angular project, I am currently relying on an asynchronous function called foo(): Promise<boolean>. Depending on the result of this function, I need to decide whether to display component Foo or Bar. Considering my specific need, what woul ...

What is the best way to test for errors thrown by async functions using chai or chai-as-promised?

Below is the function in question: async foo() : Promise<Object> { if(...) throw new Error } I'm wondering how I should go about testing whether the error is thrown. This is my current approach: it("checking for thrown error", asy ...

I am interested in using a loop in Angular to highlight my div element

Enhancing my comprehension regarding the mentioned images. If I don't select anything within the div property, the default style (css) should appear like this, at least when one div is selected. However, the issue arises when unable to select. This ...

What is the process for generating a fresh PSBT transaction using bitcoinjs-lib?

This is the code I've been working on import * as bitcoin from 'bitcoinjs-lib' const NETWORK = bitcoin.networks.regtest; const psbt = new bitcoin.Psbt({ network: NETWORK }); function p2shAddress(node: bitcoin.ECPairInterface): string { c ...

Using both Typescript and Javascript, half of the Angular2 application is built

My current project is a large JavaScript application with the majority of code written in vanilla JavaScript for a specific platform at my workplace. I am looking to convert this into a web application that can be accessed through a browser. I believe thi ...