What is the best way to retrieve attributes from union types in TypeScript?

When trying to access attributes of a union type that is not present on all types, how can it be done correctly? I keep encountering a TypeScript error stating "property ... does not exist on type..." even when checking if the attribute exists (see example below)

interface Car {
  wheels: 4,
  spareWheels: 1,
}

interface Bicycle {
  wheels: 2,
}

type Vehicle = Car | Bicycle


getWheelCount(vehicle: Vehicle): number => {
   return vehicle.spareWheels ? vehicle.spareWheels + vehicle.wheels : vehicle.wheels
}

The documentation (https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) offers a solution using 'typeof', but this approach doesn't seem to work for custom types.

Answer №1

To make use of the in operator, you can follow this example:

interface Plane {
  engines: 2;
  wings: 2;
}

interface Helicopter {
  rotors: 1;
}

type Aircraft = Plane | Helicopter;

const getEngineCount = (aircraft: Aircraft): number => {
  return "wings" in aircraft // utilizing the `in` operator
    ? aircraft.engines + aircraft.rotors
    : aircraft.engines;
};

Answer №2

If you want to distinguish between different types in Typescript, you can utilize type predicates.

interface Car {
  wheels: 4;
  spareWheels: 1;
}

interface Bicycle {
  wheels: 2;
}

type Vehicle = Car | Bicycle;

const getWheelCount = (vehicle: Vehicle): number => {
  return isVehiculeCar(vehicle) ? vehicle.spareWheels + vehicle.wheels : vehicle.wheels;
};

const isVehiculeCar = (subject: Vehicle): subject is Car => {
  return (subject as Car).spareWheels !== undefined;
};

By implementing this approach, Typescript will be able to discern whether you are referring to a Car or a Bicycle.

From a technical standpoint, Typescript deduces the type of your vehicule variable as Car only after the execution of the isVehiculeCar function. This means that if you're using an intelligent IDE with features like auto-completion, you will have access solely to the attributes of the Car interface within that specific scope.

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

How can you determine the type of an argument based on the type of another argument?

Is it possible to dynamically assign value types in the const set = (key: keyof Store, value: any) function based on the keys defined in the Store interface? For instance, setting a key foo as type number and key bar as type string[]. import store from & ...

Inquiry regarding the TS2322 error encountered in a Svelte Component

I'm currently exploring Svelte using TypeScript. I encountered a TS23 error while working on this piece of code. <script lang="ts"> import ComponentA from './ComponentA.svelte'; import ComponentB from './Compone ...

Getting a string output from a Typescript promise

Here is some Typescript code that I thought would be simple. public showDialog(theNickname: string): string { var req = { method: 'POST', url: '/Q/GetUserDetails', data: { nickname ...

The FirebaseX Ionic native plugin received 2 arguments instead of the expected 3-4

Trying to implement Firebase Phone Auth with the FirebaseX plugin, I encountered an issue. Here is the code snippet I used: async getVerificationCode(): void { const res:any = await this.firebaseX.verifyPhoneNumber('+16505553434', 60); ...

Creating components with the viewContainerRef in Angular2 is functioning as expected

When attempting to load a dynamic component into the root component using viewContainerRef.createComponent, I encountered an issue where it appended to the wrong place. https://i.stack.imgur.com/lF1yT.png Here is my code: -----app.compoment.ts----- exp ...

Strengthen the security of the index.html file within an Angular application by addressing

After running a security scan using Fortify, issues were highlighted in my application which uses an Angular front end with ASP.NET Core. One of the detected issues is related to the following line in the index.html file: document.write('base href=" ...

Customize Material-UI Icons styles in React app

I'm working on a React.js app with Typescript and I need to remove the default visited Material Icons coloring from an anchor tag. Here's the stylesheet I tried: const useStyles = makeStyles((theme: Theme) => createStyles( myAnchor: ...

Display a React Material-UI Button variant depending on the isActive state of a NavLink using TypeScript with Material-UI and React Router v

I'm attempting to dynamically change the variant of a mui Button based on the isActive state of a Navlink, but I'm running into an error <Button to="/" component={NavLink} variant={({isActive}:{isActive:any}) => isActive ? 'contained&a ...

The button is obscured by the dropdown menu

Here is the code snippet I am working with: HTML <nav class="navbar bg-dark navbar-dark"> <div class="container-fluid"> <div class="navbar-header"> <a href="#" class=&quo ...

Challenges with sorting and pagination in Angular 6's material-table

I am facing a challenge in my Angular6 material-data-table application where I need to display and manipulate a complex JSON structure received from a REST endpoint. While the data is successfully displayed, I am struggling to implement pagination and sort ...

What is the method for avoiding short-circuit conditions in TypeScript?

Is there a way to evaluate conditions in TypeScript without using short-circuiting? TypeScript does not support & or | for boolean types. I need to avoid short-circuit checking because I call the showErrors function inside the isValueValid function. C ...

Changing icons within an ngFor loop in Angular 2

Looking for a solution: How can I toggle icons using ngFor? Situation: I am using *ngFor to iterate through an array and display category names. When a day is clicked, I want to open an accordion and show category details (which I have already managed). O ...

Can you explain the difference between a public app and express.Application?

As I delved into the world of TypeScript and Node, I stumbled upon a perplexing line of code: public app: express.Application; This line is nested within the context of an import statement and a class definition. Let's take a closer look at it: i ...

Encountering the error "Element implicitly has an 'any' type because expression of type 'string' cannot be used to index type '{}'" can be frustrating when working with React TypeScript

I'm encountering an issue when trying to access an object with an id in the code below. An error message stating 'Element implicitly has an 'any' type because expression of type 'string' can't be used to index type ' ...

What is the best approach to creating customizable modules in Angular2?

I'm exploring the most effective approach to configuring modules in Angular 2. In Angular 1, this was typically achieved through providers. As providers have been altered significantly, what is the preferred method for passing configuration parameters ...

Add a feature to a functional component that is enclosed with React.forwardRef

Within my codebase, there exists a component that is wrapped with React.forwardRef and serves as a compound component. One challenge I encountered was how to preserve the functionality of Form.Item = FormItem; while still having the Form component fun ...

Firefox unable to detect click events

I am facing an issue with my Angular 2 website where it is not functioning correctly in Firefox. The main problem lies in the fact that Firefox does not recognize the event being passed into my TypeScript function. This event specifically pertains to a mou ...

Using TypeScript to define parameter types to update an object's key and value

I need assistance in creating a function that can update an object's value based on the provided key and new value while ensuring type safety. type GroceryStore = { isOpen: boolean; offers: string[]; name: string; }; const myGroceryStore: ...

What causes the variation in typing behavior between specifying props directly on a component versus nesting them inside another prop?

Understanding the next component might be a bit tricky, so let's delve into it (Check playground): type Props<T> = { initValue: T, process: (value: T) => T } export const Input = <T,>({ initValue, process, }: Props<T>): ...

Can classes from an external package be imported into an Angular library within an Angular app using Openlayers?

I am currently developing an Angular library that configures an OpenLayers map as an Angular component. The component is functioning properly, but I need to access classes and constants from a package imported by the library, specifically OpenLayers. To w ...