Check if the provided string is part of the available options in Typescript

Whenever I create an if statement in typescript to check if a variable is either "a" or "b"

if (str === "a" || str === "b") {
    // typescript recognizes that the value can only be "a" or "b"
}

However, this approach can become too verbose, especially when dealing with multiple options.

Is there a more concise way of achieving the same result in typescript? Perhaps something like this:

if (["a", "b"].includes(str)) {
    // Unfortunately, typescript cannot infer that it is limited to just "a" or "b"
}

This example may seem oversimplified, but for a more comprehensive scenario, consider identifying if a string corresponds to a boolean property within an interface:

interface Filters {
    isPromo?: boolean,
    isFreeShipping?: boolean,
    isNew?: boolean,
    isInStock?: boolean,
    title?: string
}

let filters: Filters = {};

for (const filterValuePair of location.search.split("&")) {
    const [urlFilter, value] = filterValuePair.split("=");
    // In this case, typescript provides no warnings as it deduces the necessity for a boolean property due to the nature of the "if" statement
    if (urlFilter === "isPromo" || urlFilter === "isFreeShipping" || urlFilter === "isNew" || urlFilter === "isInStock") {
        filters[urlFilter] = Boolean(value);
    }
    // The following method is briefer but lacks type inference from typescript
    if (["isPromo", "isFreeShipping", "isNew", "isInStock"].includes(urlFilter)) {
        filters[urlFilter] = Boolean(value);
    }
}

Check out the playground here

Answer â„–1

Utilizing a custom type guard can help in ensuring that if a certain condition is met, then a variable belongs to a specific type.

The function implementation uses the method includes to confirm the type based on the return value.

const isFilterKey = <K extends string & keyof Filters>(
    properties: K[], urlFilter: string
): urlFilter is K => {
    return (properties as string[]).includes(urlFilter);
}

The code

(properties as string[]).includes(urlFilter)
is used instead of just properties.includes(urlFilter), as properties has type K[], requiring includes to be called with a K variable. Alternatively,
properties.includes(urlFilter as K)
could also work, but the former version is more semantically accurate considering we know properties is within string[] subset, however, it's uncertain if urlFilter is of type K.

if (isFilterKey(["isPromo", "isFreeShipping", "isNew", "isInStock"], urlFilter)) {
    filters[urlFilter] = Boolean(value);
}

In this scenario, assigning filters[urlFilter] is permissible since the type of urlFilter is established as the union of keys in the array.

Interactive Demo Link

A broader perspective, such as in your "a" | "b" instance, the typeguard would appear as:

const isSpecificString = <K extends string>(
    strings: K[], value: string
): value is K => {
    return (strings as string[]).includes(value);
}

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

Encountering an undefined error while attempting to retrieve an object from an array by index in Angular

Once the page is loaded, it retrieves data on countries from my rest api. When a user selects a country, it then loads the corresponding cities for that country. Everything is functioning properly up to this point, however, upon opening the page, the city ...

Error TS2614: The module does not have a member named 'NextHandleFunction' that can be exported

Error: node_modules/@types/body-parser/index.d.ts:14:10 - error TS2614: Module '"../../../src/connect"' has no exported member 'NextHandleFunction'. Did you mean to use 'import NextHandleFunction from "../../../src/c ...

Angular mat-table experiencing issues with matToolTip functionality

My Angular project is using Angular Material 16x, but for some reason, the matToolTip is not displaying at all. I have experimented with various versions, including a basic matTooltip="hello world", but I just can't seem to get it to work. I have come ...

Having trouble with MUI auto import suggestions in my Next.js 13 project on VS Code

I'm currently developing a project using Next.js 13 and have installed MUI. However, I am encountering an issue where VS Code is not providing auto imports from the @mui/material library, as shown in the attached screenshot. https://i.stack.imgur.com ...

Steps for linking HTTP requests in Angular 2 depending on the type of response

My attempt to create an api call from a remote server and then, if an error occurs, make another request from my local server is not working as expected. I am encountering errors and need help to determine if my approach is feasible. Here is the code snip ...

"Utilizing the power of union types within a generic function

Here is some code I am working with: /** Explains why there is no value */ export interface None { 'is none because': string; // Includes spaces to decrease the chance of confusion with a non-None member } /** Represents either a value ...

An issue has occurred with the NullInjector, specifically regarding the AppModule and Storage in Ionic 4

When attempting to launch my Ionic app using npm start, an error message appears stating "NullInjectorError: No provider for Storage!". I have already included Storage in the app.module.ts file as shown below: imports: \[ BrowserModule, IonicModule ...

Find the sum of individual data points in chart.js by taking into consideration their respective

I created a line chart using the Chart.js library. My goal is to calculate the weighted sum when hovering over a specific data point, based on the difference between that point and its neighboring points. For instance, if point[0] = 5 with weight 2, point[ ...

Automatically export as a namespace in a declaration file

I have a compact TypeScript library that is exported as UMD, and I generate the *.d.ts file automatically by setting "declaration": true in my tsconfig. The exported file contains: export class Blue { alert(): void { console.log('alerte ...

arrange elements by their relationship with parents and children using typescript and angular

Here is a list that needs to be sorted by parent and child relationships: 0: {id: 7, name: "333", code: "333", type: 3, hasParent: true, parentId: 4} 1: {id: 6, name: "dfgdfg", code: "dfgdfg", type: 3, hasParent: false, parentId: null} 2: {id: 5, name: ...

What is the best way to transform a synchronous function call into an observable?

Is there a conventional method or developer in RxJS 6 library that can transform a function call into an observable, as shown below? const liftFun = fun => { try { return of(fun()) } catch (err) { return throwError(err) } ...

Tips for executing "TS" code snippets using ts-node?

When referencing Solana documentation, TypeScript code snippets are commonly used. For instance, in the link provided below (the first code snippet) should be executed to return a value: I attempted to execute the initial snippet using: ts-node file.ts, h ...

Preventing Event Propagation in Angular HTML

I am encountering an issue with stopPropagation, and I need assistance with implementing it in HTML and TypeScript for Angular. The problem is that the dialog opens but also triggers a propagation. Below is my code snippet in HTML: <label for="tab-two ...

Using a Javascript library within an Angular component: A comprehensive guide

I've been working on a Web-Client project that involves visualizing sensor data such as velocity and acceleration within a coordinate system. In order to display this coordinate system, I decided to use the graph.js library from https://github.com/dhu ...

What is the best way to add a service to a view component?

I am facing an issue with my layout component where I am trying to inject a service, but it is coming up as undefined in my code snippet below: import {BaseLayout, LogEvent, Layout} from "ts-log-debug"; import {formatLogData} from "@tsed/common/node_modul ...

Chrome Not Responding to Angular5 Debugging

I'm facing an issue where I used to be able to set breakpoints in my Angular code using developer tools, and it would pause correctly. However, recently the network files are not being mapped to my local files properly. For a detailed explanation, ple ...

The imported path is not found in Tsconfig

Hey there! I've been working on getting my project's imports to play nice with typescript import paths. Every time I encounter this error : Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'app' imported from dist/index.js It seems l ...

Ways to determine if an object belongs to a union type

In my programming project, I am dealing with two specific interfaces: TypeA and TypeB. The React script I'm working on accepts an object called Object that is of type TypeA|TypeB. Within the script, there's a function named doSomething(attribut ...

Child component does not detect changes in @Input array

I am working with an angular2 parent component that looks like this: ParentComponent { some_array : Array; (...) } Its child component is structured as follows: ChildComponent { selector: "child" @Input some_object : Object; } In ...

There is no initial value set for the property and it is not definitively assigned in the constructor

I encountered an issue while working on the following code snippet: export class UserComponent implements OnInit { user: User; constructor() { } ngOnInit() { this.user = { firstName : "test", lastName ...