Restricting enum type to only one member

enum Value {
    First,
    Second,
}

interface Data {
    value: Value
    number: number
}

interface SubData {
    value: Value.Second
}

function calculation(input: SubData){
    return;
}

function initiate(){
    const input : Data = {
        number: 100,
        value: Value.Second
    }

    if(input.value !== Value.Second) return;
    
    calculation(input)
                 // ^^^^ Types of property 'value' are incompatible.     
                 //      Type 'Value' is not assignable to type 'Value.Second'.
}

Playground

  1. If SubData and Data had the same fields, we could use a type predicate to narrow it down. But my problem requires that SubData will only have a subset of the fields of Data. Therefore a type predicate wouldn't work [playground].

  2. We could also change the type of value in the interface SubData to Value. And then move the if check for the second value inside calculation function. But let's also say I don't want to do that. I don't want to give the function this responsibility.

  3. We could create a new object of type SubData based on the original object and then pass that to calculation() instead. But this feels like a workaround (and extra code) because we couldn't narrow down the type [playground].

Is there a way to properly narrow down the type without breaking the rules? (no any or casting)

Answer №1

To determine whether the item is of type MetersMeasurement or Measurement, you can employ a method known as a type guard.

enum Unit {
    Kilometer,
    Meter,
}

interface Measurement {
    distanceUnit: Unit;
    distance: number;
}

interface MetersMeasurement {
    distanceUnit: Unit.Meter;
}

function someCalculation(item: MetersMeasurement){
    return;
}

function isMeasurement(obj: Measurement): obj is Measurement {
  return (obj as Measurement).distance !== undefined;
}

function main(){
    const item = {
        distance: 100,
        distanceUnit: Unit.Meter
    }

    if(isMeasurement(item)) return;
    
    someCalculation(item)
}

Answer №2

Give this a try:

enum Unit {
    Kilometer,
    Meter,
}

type Distance = {
    distance: number;
}

type MetersMeasurement = {
    distanceUnit: Unit.Meter;
} & Distance

type KilometersMeasurement = {
    distanceUnit: Unit.Kilometer;
} & Distance

type Measurement = MetersMeasurement | KilometersMeasurement;


/*
 * output is in kilometers
 */
function meterToKilometerConversion(item: MetersMeasurement) {
    return item.distance * .001;
}

function main(){
    const item : Measurement = {
        distance: 100,
        distanceUnit: Unit.Meter
    }

    if (item.distanceUnit == Unit.Meter) {
        meterToKilometerConversion(item);
    }
}

Playground

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

When I select a checkbox in Angular 2, the checkall function does not continue to mark the selected checkbox

How can I check if a checkbox is already marked when the selectAll method is applied, and then continue marking it instead of toggling it? selectAll() { for (let i = 0; i < this.suppliersCheckbox.length; i++) { if (this.suppliersCheckbox[i].type == " ...

When an import is included, a Typescript self-executing function will fail to run

Looking at this Typescript code: (()=> { console.log('called boot'); // 'called boot' })(); The resulting JavaScript is: (function () { console.log('called boot'); })(); define("StockMarketService", ["require", "exp ...

Struggling to incorporate generics into a Typescript method without sacrificing the typing of object keys

Currently, I am working on a method in Typescript that is responsible for extracting allowable property types from an object of a constrained generic type. The scenario involves a type called ParticipantBase which consists of properties like first: string ...

Deploying Angular to a shared drive can be done in a

My angular.json file contains the following line: "outputPath": "Y:\Sites\MySite", After running ng build, I encountered the error message: An unhandled exception occurred: ENOENT: no such file or directory, mkdir 'D:& ...

Could an OpaqueToken be assigned using an observable?

I am attempting to establish an opaque token in the providers using an observable. The purpose behind this is that I am retrieving the value through the Http provider (from an external JSON file). This is my current approach: { provide: SOME_ ...

What is a more precise way to define an Object type on a temporary basis?

I'm currently working with Angular 2. Typically, when I specify a type, I start by creating an interface: interface Product { name: string, count: number } and then use it like this: let product: Product; However, now I need to temporarily de ...

Locate and retrieve the item that appears most often in a given array

In order to determine the mode of an array consisting of integer numbers only, I must create a function named findMode. If the array is empty, the function should return 0. Otherwise, it should return the element that occurs most frequently in the array. I ...

The TypeScript compiler is indicating that the Observable HttpEvent cannot be assigned to the type Observable

Utilizing REST API in my angular application requires me to create a service class in typescript. The goal is to dynamically switch between different url endpoints and pass specific headers based on the selected environment. For instance: if the environmen ...

Having trouble with JavaScript's Date.getUTCMilliSeconds() function?

I have a straightforward question for you. Take a look at this Angular App and try to create a new date, then print the number of UTC milliseconds of that date in the console. Can you figure out why it is returning zero? ...

Leveraging the Cache-Control header in react-query for optimal data caching

Is it possible for the react-query library to consider the Cache-Control header sent by the server? I am interested in dynamically setting the staleTime based on server instructions regarding cache duration. While reviewing the documentation, I didn&apos ...

Ensuring thoroughness in validation without the use of specific text strings

Implementing the assignment or assertion of never at the end of a function is a strategy commonly used in Typescript to ensure exhaustive checks at compile time. To enable the compiler to recognize this, explicit strings are needed for it to check against ...

Error: Missing provider for MatBottomSheetRef

While experimenting in this StackBlitz, I encountered the following error message (even though the MatBottomSheetModule is imported): ERROR Error: StaticInjectorError(AppModule)[CountryCodeSelectComponent -> MatBottomSheetRef]: S ...

Having trouble getting anime.js to function properly in an Ionic 3 project?

I have been attempting to incorporate anime.js into my Ionic 3 project, but I keep encountering an error when using the function anime({}) in the .ts file. Error: Uncaught (in promise): TypeError: __webpack_require__.i(...) is not a function TypeError: _ ...

I am verifying the user's login status and directing them to the login page if they are not already logged in

My goal is to utilize ionViewWillEnter in order to verify if the user is logged in. If the check returns false, I want to direct them to the login page and then proceed with the initializeapp function. My experience with Angular and Ionic is still limite ...

When executing npm release alongside webpack, an error is triggered

Currently, I am following a tutorial provided by Microsoft. You can access it through this link: https://learn.microsoft.com/en-us/aspnet/core/tutorials/signalr-typescript-webpack?view=aspnetcore-3.1&tabs=visual-studio However, when attempting to run ...

Decorator used in identifying the superclass in Typescript

I am working with an abstract class that looks like this export abstract class Foo { public f1() { } } and I have two classes that extend the base class export class Boo extends Foo { } export class Moo extends Foo { } Recently, I created a custom ...

Angular 2/4 throws an Error when a Promise is rejected

I implemented an asynchronous validator function as shown below. static shouldBeUnique(control: AbstractControl): Promise<ValidationErrors | null> { return new Promise((resolve, reject) => { setTimeout(() => { if (contr ...

What happens when i18next's fallbackLng takes precedence over changeLanguage?

I am currently developing a Node.js app with support for multi-language functionality based on the URL query string. I have implemented the i18next module in my project. Below is a snippet from my main index.ts file: ... import i18next from 'i18next& ...

Can a React function component be typed with TypeScript without the need for arrow functions?

Here is my current React component typed in a specific way: import React, { FunctionComponent } from "react"; const HelloWorld : FunctionComponent = () => { return ( <div> Hello </div> ); } export default HelloWorld; I ...

Tips for creating an input box that only accepts floating point numbers:

I have a custom component - a text box that I am using in two different places. In one location, it accepts integers and in another, floats. For the integer validation (where dataType=2), I have successfully implemented it. However, for the float validat ...