Is it possible to retrieve a union type property as an array of values in order to conduct a flexible type validation process?

Currently, my code looks something like this:

interface Apple {
  type: 'Apple'
}

interface Banana {
  type: 'Banana'
}

interface Coconut {
  type: 'Coconut'
}

type Fruit = Apple | Banana | Coconut

type AppleOrBanana = Apple | Banana

const returnOnlyApplesOrBananas = (fruit: Fruit): Apple => {
  if (fruit.type === 'Apple' || fruit.type === 'Banana') {
    return fruit;
  }

  throw new Error('Unexpected type of fruit');
}

It typechecks successfully,

but the issue is that my actual 'Fruit' type is a much larger union.

I would really like to be able to do something like this:

const IdealReturnOnlyApplesOrBananas = (fruit: Fruit): Apple => {
  if (AppleOrBanana['type'].includes(fruit.type)) {
    return fruit;
  }

  throw new Error('Unexpected type of fruit');
}

It seems possible since the type checker knows what AppleOrBanana['type'] is because it's a type... I know how to define types based on constant arrays, so I'm wondering if the reverse is achievable.

If not, are there any smart techniques or patterns that could simplify my situation? Such as narrowing down a large union type to a smaller one safely.

Answer №1

Implementing a Type Predicate could be a step in the right direction theoretically, as it allows for any predicate function. While not an exact solution, it might facilitate achieving the desired outcome.

Link to Code Playground

const isAorB = (x: AorBorC): x is AorB => {
    return ["A", "B"].includes(x.type)
}

const returnOnlyAorBs = (x: AorBorC): AorB => {
  if (isAorB(x)) {
    return x;
  }

  throw new Error('unexpected type');
}

Another approach with similarities could involve utilizing enums, as they are Typescript artifacts that persist at runtime. However, using an enum in this manner may not be optimal and could introduce fragility.

Link to Code Playground

enum Types {
  A,
  B,
  C
}

const isAorB = (x: AorBorC): x is AorB => {
    return x.type < Types.C
}

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

The 'substr' property is not found in the type 'string | string[]'

Recently, I had a JavaScript code that was working fine. Now, I'm in the process of converting it to TypeScript. var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; if (ip.substr(0, 7) == "::ffff ...

Implementing a feature in Typescript/React component that provides autocomplete functionality

Currently, I have developed a TypeScript and React component that has been published on NPM. My goal is to enable IntelliSense to autocomplete React props for this component. While I typically use JSDoc for plain React components, it does not seem to work ...

Tips for transforming an Observable stream into an Observable Array

My goal is to fetch a list of dogs from a database and return it as an Observable<Dog[]>. However, whenever I attempt to convert the incoming stream to an array by using toArray() or any other method, no data is returned when calling the retrieveDo ...

The most secure method for retrieving User Id in AngularFire2

I'm currently facing a dilemma in determining the most secure method to obtain an authenticated user's uid using AngularFire2. There seem to be two viable approaches available, but I am uncertain about which one offers the best security measures ...

How to effectively handle null in Typescript when accessing types with index signatures unsafely

Why am I getting an error that test might be potentially undefined even though I've enabled strictNullCheck in my tsconfig.json file? (I'm unsure of the keys beforehand) const a: Record<string, {value: string}> = {} a["test"].va ...

JEST: Troubleshooting why a test case within a function is not receiving input from the constructor

When writing test cases wrapped inside a class, I encountered an issue where the URL value was not being initialized due to dependencies in the beforeAll/beforeEach block. This resulted in the failure of the test case execution as the URL value was not acc ...

Incorporating AngularFire2 in the latest Angular 11.0.5 framework

I have been attempting to utilize Firebase as a database for my angular application. Following the guidance provided in these instructions (located on the official developers Github page), I first installed npm install angularfire2 firebase --save in my p ...

What is the best way to update typings.json and typing files?

Here is the structure of my typings.json: { "globalDependencies": { "aws-sdk": "registry:dt/aws-sdk#0.0.0+20160606153210" }, "dependencies": { "lodash": "registry:npm/lodash#4.0.0+20160416211519" } } Currently, I find it tedious to update ...

Convert TypeScript-specific statements into standard JavaScript code

For my nextjs frontend, I want to integrate authentication using a keycloak server. I came across this helpful example on how to implement it. The only issue is that the example is in typescript and I need to adapt it for my javascript application. Being u ...

Creating a React Native project without the use of TypeScript

Recently I dived into the world of React Native and decided to start a project using React Native CLI. However, I was surprised to find out that it uses TypeScript by default. Is there a way for me to create a project using React Native CLI without TypeS ...

Problem with Extending Jest Matchers in VS Code TypeScript

I've developed unique Jest matchers to enhance expect for handling AxiosResponse objects. Although I've followed the standard method for expanding Jest's matcher types, my custom matchers are not being recognized by TypeScript. The error di ...

The display of the selected input is not appearing when the map function is utilized

I am attempting to use Material UI Select, but it is not functioning as expected. When I use the map function, the default value is not displayed as I would like it to be. However, it does work properly when using the traditional method. *** The Method th ...

AngularJS Dilemma: Virtual Machine Data Set but No Rendering in Sight

Below is the AngularJS controller code written in Typescript: /// <reference path='../../definitions.d.ts' /> module baseApp.viewControls.products { export interface IProductsScope extends IAppScope { vm: { product ...

Setting the "status" of a queue: A step-by-step guide

I created a function to add a job to the queue with the following code: async addJob(someParameters: SomeParameters): Promise<void> { await this.saveToDb(someParameters); try { await this.jobQueue.add('job', ...

Guide to iterating through different endpoints in a predetermined sequence

I am facing a challenge with testing various endpoints using different login credentials. When looping through the endpoints, the results are not appearing in the sequential order due to asynchronous nature. My goal is to iterate through each endpoint wit ...

Using custom hooks in JSX triggers a TypeScript error when the returned component is accessed

i just created a custom hook // useDropdown.ts function useDropdown(defaultState: number, options: number[]) { const [state, setState] = useState(defaultState); function Dropdown({ name }: { name: string }) { return ( <> <sel ...

Ensure that Angular resolver holds off until all images are loaded

Is there a way to make the resolver wait for images from the API before displaying the page in Angular? Currently, it displays the page first and then attempts to retrieve the post images. @Injectable() export class DataResolverService implements Resolv ...

Theme customization in Material UI includes the addition of a custom color. However, this custom color is missing from the control values in Story

Currently in my project, I am utilizing a stack that includes React 18, TypeScript, MUI 5, and Storybook 6.5. I have been attempting to incorporate custom colors into my MUI Theme and have them reflect in Storybook's dropdown options for the color p ...

Patiently waiting for the component variable to be assigned through subscription

I am facing an issue with two calls in my component. The second call depends on the result from the first call. In the first call, I set the value for my component variable "locked". The second call should only be executed when the result is true, meaning ...

Guide: Ensuring the validity of an object retrieved from a database with Nest.js class-validator

When activating a user, I need to ensure that certain optional data in the database is not empty by using class-validator dto. So far, my controller level validations for body, query, and all other aspects have been successful. The DTO file contains vali ...