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

Issues arising when routing ffmpeg to flac encoder

I am facing an issue with encoding a flac file with seektables. The ffmpeg's flac encoder does not include seektables, so I have to resort to using the flac Command Line Interface (CLI). My goal is to convert any arbitrary audio file into a seekable f ...

Exploring Angular2's ability to interpret directive templates using the ng-container

Recently delving into angular2, I ventured into creating dynamic forms and generating fields by following the guide provided in this URL. The result was as expected. The dynamic form component renders each field one by one using ng-container, like shown b ...

Limit the selected values to calculate a partial sum

Imagine two distinct classes called professor and student: professor.ts export class Professor { id: number name: string } student.ts import { Professor } from "./professor" export class Student { ...

Discrepancy between code, output from ng build, and how the browser is

I am in the process of developing an Angular 13 library that includes two services and a group of models. These services consist of an authentication service and a client service. However, after building the library, I noticed some global variables missing ...

React with Typescript allows us to refine the callback type depending on the presence of an optional boolean prop

In my project, there's a component <Selector /> that can optionally accept a parameter called isMulti: boolean. It also requires another parameter called onSelected, whose signature needs to change depending on the value of isMulti (whether it i ...

The combination of Next.JS and React Objects is not acceptable as a React child

Summary: Encountering the error Error: Objects are not valid as a React child (found: [object Promise]) while making a fetch request in a Typescript project. Interestingly, the same code snippet works without errors in a Javascript project. Recently, I ...

What is the significance of having nodejs installed in order to run typescript?

What is the reason behind needing Node.js installed before installing TypeScript if we transpile typescript into JavaScript using tsc and run our code in the browser, not locally? ...

Experiencing an error message stating 'The token ${Token[TOKEN.72]} is invalid' while using cdk synth, specifically when trying to assign the value of ec2.Vpc.cidr from cfnParameter.value

Attempting to utilize the AWS CDK CfnParameter to parameterize the CIDR value of ec2.Vpc. The aim is to make the stack reusable for VPC creation with the CIDR as a customizable value. An error stating "${Token[TOKEN.72]} is not valid" occurs during synthe ...

Navigating to a different page in Ionic 2 upon app initialization

Is there a way to automatically redirect the page to the home page instead of displaying the login page if there is already a token stored in localStorage? I currently have the following code in the constructor() of app.component.ts, but it still display ...

Trouble encountered while using useRef in TypeScript

I'm encountering an issue with the code below; App.tsx export default function App() { const [canvasRef, canvasWidth, canvasHeight] = useCanvas(); return ( <div> <canvas ref={canvasRef} /> </div> ) ...

Updating Select Options Disabled/Enabled in Angular 2

In my Angular2 project, I have 2 select elements: <div ng-controller="ExampleController"> <form name="myForm"> <label for="companySelect"> Company: </label> <select name="companySelect" id= ...

I continue to encounter the same error while attempting to deliver data to this form

Encountering an error that says: TypeError: Cannot read properties of null (reading 'persist') useEffect(() => { if (edit) { console.log(item) setValues(item!); } document.body.style.overflow = showModal ? "hidden ...

What could be causing this TypeScript class to not perform as anticipated?

My goal with this code snippet is to achieve the following: Retrieve a template using $.get(...), Attach an event listener to the input element within the template I am using webpack to transpile the code without encountering any issues. The actual cod ...

The function cannot be accessed during the unit test

I have just created a new project in VueJS and incorporated TypeScript into it. Below is my component along with some testing methods: <template> <div></div> </template> <script lang="ts"> import { Component, Vue } from ...

There seems to be an issue with the TypeScript error: it does not recognize the property on the options

I have an item that looks like this: let options = {title: "", buttons: undefined} However, I would like to include a function, such as the following: options.open() {...} TypeScript is giving an error message: property does not exist on the options ty ...

Display various react components based on the value of the property

I am in the process of creating an input component in ReactJs with typescript. The input can vary in types such as text, date, select, or textarea. Depending on the type provided, the displayed control will differ. For example, if set to text, <input t ...

Encountered difficulty locating the module path 'stream/promises'

When importing the following in a typescript nodejs app import { pipeline } from "stream/promises"; Visual Studio Code (vscode) / eslint is showing an error message Unable to resolve path to module 'stream/promises' This issue appeare ...

"Encountered a TypeScript error (2345) when using customElements.define() in Lit 2

When we upgraded various lit-Components to version 2.1.1 "lit": "2.1.1", a TypeScript error surfaced: The argument 'typeof MyComponent' cannot be assigned to a parameter of type 'CustomElementConstructor'. The &apo ...

What is the way to imitate a variable with Jasmine Spy?

Trying to troubleshoot a login feature, how can I mock everything except string variables? @Component({ selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.scss']) export c ...

Ensure that compiler errors are eliminated for object properties that do not exist

Coming from a JavaScript background, I recently began working with Angular 2 and TypeScript. Below is a snippet of my code: export class AddunitsComponent implements OnInit { public centers:any; constructor(){ this.centers = {}; }} In my view, I h ...