Verifying the eligibility of a value for a union type

In my app, there is a type called PiiType that enforces strong typing:

type PiiType = 'name' | 'address' | 'email';

When receiving potentially sensitive information from the server, we need to verify if it aligns with this defined type.

A solution proposed on Stack Overflow suggests creating a duplicate array of valid values and checking against it:

isValidPii(value: string): Boolean {
  const piiTypeValues = ['name', 'address', 'email'];
  return piiTypeValues.indexOf(potentialValue) !== -1;
}

This method is not ideal as it involves defining the type twice, which can lead to errors. Is there a way to check the validity of a value without duplicating its definition?

If there was an operator like isoftype, the validation process could be simplified:

'name' isoftype PiiType;      // true
'hamburger' isoftype PiiType; // false
100 isoftype PiiType;         // false

Since such an operator doesn't exist, what alternative approach can be taken to validate a value against this union type?

We are considering using enums instead of native types for representing this typing, but would like to explore other options first.

Answer №1

Although duplicating the union may not be the most ideal solution, utilizing the compiler can help ensure that the union and duplicated values remain in sync. If you do not have control over the union, this method provides a safe alternative (otherwise, consider @Matt-McCutchen's solution).

We can exploit mapped types and excess object literal properties check to develop a function that accepts an object with identical keys as the union. The values of the object are insignificant; we simply utilize the literal type 0.

type PiiType = 'name' | 'address' | 'email';

function isValidBuilder<T extends string>(o: Record<T, 0>) {
  let values = Object.keys(o)
  return function (v: string): v is T {
    return values.indexOf(v) !== -1
  }
}

const isValidPii = isValidBuilder<PiiType>({
  name: 0,
  address: 0,
  email:0
})

// Error  missing key
const isValidPii2 = isValidBuilder<PiiType>({
  name: 0,
  address: 0,

})

//error excess key
const isValidPii4 = isValidBuilder<PiiType>({
  name: 0,
  address: 0,
  email: 0
  other:0
})

Answer №2

One way to achieve this is by running the array through a function that identifies an element type restricted to string. This will prompt the compiler to identify a collection of literal types:

function asLiterals<T extends string>(arr: T[]): T[] { return arr; }
const piiTypeValues = asLiterals(['name', 'address', 'email']);
type PiiType = (typeof piiTypeValues)[number];

While there's an alternative solution mentioned here, the method above appears to be more straightforward.

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

Leverage C# model classes within your Angular application

Just wanted to express my gratitude in advance import { Component, Inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Component({ selector: 'app-fetch-data', templateUrl: './fetch-data. ...

Modify the data in the local storage and showcase it on the webpage without the need to refresh the page

Currently, I am working on a project using Angular 8. One of the issues I am facing is with a variable called 'cartproductitems'. I want this variable to update automatically whenever a user adds a new product to the cart, so that the number of i ...

Experiencing a problem in React JS when trying to render a component?

I encountered an error message while trying to render a component from an object. Type 'FC<Boxprops> | ExoticComponent<{ children?: ReactNode; }>' is not compatible with type 'FC<Boxprops>'. Type 'ExoticComponen ...

Utilizing string to access property

Is there a better way to access interface/class properties using strings? Consider the following interface: interface Type { nestedProperty: { a: number b: number } } I want to set nested properties using array iteration: let myType: Type = ...

Creating a tsconfig.json file that aligns perfectly with your package.json and tsc command: a step-by-step

I've chosen to use TodoMvc Typescript-Angular as the starting point for my AngularJS project. Everything is working smoothly so far. Here's a breakdown of what I can do: To manage all dependencies, I simply run npm install or npm update based o ...

Certain sections within a Formik form are failing to update as intended

I have successfully implemented a custom TextField wrapper for Material-UI fields, but I am facing an issue with native Material UI fields not updating the form data upon submission. Below is the relevant code snippet along with a link to a code sandbox d ...

Relationship between Angular Components - Understanding the Connection

I am facing a challenge with two components, one located in the shared folder and the other in the components folder. The component in the components folder contains a button that, when clicked, triggers a function from my globalFilterService in the serv ...

typescript ways to exclude enum values

I am working with enums in TypeScript. enum Status { Cancelled = 'cancelled', Completed = 'completed', Created = 'created' } Now, I need to create another enum that includes only the values Completed and Created. enum S ...

Dealing with Typescript (at-loader) compilation issues within a WebPack environment

Currently, I am using Visual Studio 2017 for writing an Angular SPA, but I rely on WebPack to run it. The current setup involves VS building the Typescript into JS, which is then utilized by WebPack to create the build artifact. However, I am looking to t ...

The newDragSource() function is not functioning properly within golden-layout version 2.6.0

We are currently in the process of migrating from golden-layout version 1.5.9 to version 2.6.0 within a large Angular 16 production application, albeit slowly and somewhat painfully. Within our application, there exists a dropdown menu that displays the n ...

What is the best way to showcase the information retrieved from my API?

I am attempting to display the ID and Document number that are retrieved from an array. Data Returned However, I am not seeing any results in return. You can view the application results here. I have tried using string interpolation like {{document.id}} ...

Encountered an error while attempting to compare 'true' within the ngDoCheck() function in Angular2

Getting Started Greetings! I am a novice in the world of Angular2, Typescript, and StackOverflow.com. I am facing an issue that I hope you can assist me with. I have successfully created a collapse animation for a button using ngOnChanges() when the butto ...

What is the process of adding an m4v video to a create-next-app using typescript?

I encountered an issue with the following error: ./components/Hero.tsx:2:0 Module not found: Can't resolve '../media/HeroVideo1-Red-Compressed.m4v' 1 | import React, { useState } from 'react'; > 2 | import Video from '../ ...

Bidirectional data binding on the table

I am struggling to implement two-way data binding in a table between my .ts and my .html files. I have a structure that adds a new equipment to the array, and I want that new equipment to display on the table within the same screen. I believe it involves ...

Ways to delete a class in typescript

There's a menu on my website with li tags containing an a element for navigation. Everything is working fine, but I'm facing an issue where I need to remove all elements with the class seleccionado and only add it to the clicked li. I tried using ...

TypeScript - patiently anticipating the completion of nested for loops

Currently, I am working on a task that involves implementing two nested for loops in my code. The primary objective of the first loop is to make an API call, which is dependent on the IDs selected by the user. Unfortunately, the limitation of passing only ...

An array of Promise<Employee> cannot be used as a parameter for an array of type Employee[]

I am currently facing an issue with loading my Collection of Employees from a Firestore Database and fetching a 'Workday' for each Employee, which is stored as a Document in a Subcollection named 'Employees'. Below is the code snippet I ...

What is the best way to define several mapped types in TypeScript?

Imagine you have the following lines of TypeScript code: type fruit = "apple" | "banana" | "pear" type color = "red" | "yellow" | "green" You want to define a type that includes a numeric propert ...

Dependency Injection: The constructor of the injectable class is called multiple times

There are multiple classes that inject the TermsExchangeService: import {TermsExchangeService} from './terms-exchange.service'; @injectable() export class TermsExchangeComponent { constructor( private termsExchangeService: TermsExchan ...

Struggling with the compilation of this Typescript code

Encountering a compile error: error TS2339: Property 'waitForElementVisible' does not exist on type 'signinPage' SigninPage code snippet: export class signinPage{ constructor(){ emailInput: { selector: 'input[type ...