What is the best way to search for a specific value in the Record definition?

In the documentation for Typescript, a type is defined to be used as keys into a Record<>. It seems like this is done to restrict and secure the keys that can be utilized.

type CatName = "miffy" | "boris" | "mordred";

What exactly is this type? How can I search through it to check if it includes a specific string value, like checking if "bart" is one of its allowed values?

If we consider the earlier union type being used as a key in a Record based on the docs:

const cats: Record<CatName, CatInfo> = {}

But what happens if, during runtime, we receive data for a cat name not included in the predefined list, for example 'bart', and try to add an entry for that new cat name? Will this result in an error?

Answer №1

TypeScript's type system is specifically for compilation purposes; it does not provide runtime value checking. To perform such checks, you should define your list as an Array or Set.

const CAT_NAMES = ["miffy", "boris", "mordred"] as const;
type CatName2 = typeof CAT_NAMES[number];
  • as const serves as a const assertion. By using it, you assure TypeScript that the values in CAT_NAMES will remain unchanged, resulting in the typing of CAT_NAMES as
    readonly ["miffy", "boris", "mordred"]
    , rather than a simple string[].
  • typeof CAT_NAMES[number] extracts the types of the array values, aiding in accessing the CAT_NAMES list without repetition.

You can utilize the Record type to specify the names as valid keys. However, caution is advised: if TypeScript assumes these values are part of a limited list, it may struggle when presented with an arbitrary string for testing. This concern applies if you define your wire format type to be of type CatName but validate against arbitrary strings; fortunately, Object.keys returns string[].

function checkNameWithoutCast(name: string): name is CatName {
  // Error: passing the wrong type (string) to `includes`,
  // as `includes` demands ("miffy" | "boris" | "mordred")!
  return CAT_NAMES.includes(name);
}

function checkName(name: string): name is CatName {
  // You could cast to string[], or cast `name` to CatName.
  return (CAT_NAMES as ReadonlyArray<string>).includes(name);
}

function yourFunction(name: string) {
  if (checkName(name)) {  // name is type (string)
    console.log(name);    // name is type ("miffy" | "boris" | "mordred")
  }
}
  • name is CatName2 acts as a type predicate. While returning a boolean is possible, employing a type predicate allows TypeScript to streamline the type narrowing process from string, as demonstrated in yourFunction.
  • Array.includes(...) and Array.indexOf(...) != -1 can function here, but for lengthy lists, transitioning to aSet alongside Set.has can optimize operations from linear-time O(n) to logarithmic-time O(log n) or constant-time O(1).

Playground Link

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

"Implementing a date picker in your Ionic 5 app: A step-by-step

How can I integrate a date picker similar to the Angular Material Date picker into my Ionic 5 application? I prefer not to use the native ion-datetime component due to limitations such as incomplete calendar display and lack of support for alternative ca ...

The issue of ngModel not binding to the value of ion-select in Angular Ionic

Having an ion select outside of a form with an ngModel attribute bound to "selectedValue", I encounter an issue where my selections are not being properly populated in the selectedValue variable even though they appear in the ionChange method. The main pur ...

Directive for displaying multiple rows in an Angular table using material design

I am attempting to create a dynamic datatable with expandable rows using mat-table from the material angular 2 framework. Each row has the capability of containing subrows. The data for my rows is structured as an object that may also include other sub-ob ...

The swipe motion will be executed two times

By pressing the Circle button, the Box will shift to the right and vanish from view. Further details (FW/tool version, etc.) react scss Typescript framer-motion import "./style.scss"; import React, { FunctionComponent, useState } from &q ...

Error encountered with the root reducer due to data type mismatch

Within my Redux store setup, I have a persistedReducer initialized to include the redux-persist config and the "rootReducer": client/src/redux/store.ts: import { configureStore } from '@reduxjs/toolkit'; import { persistStore, persistReducer } f ...

The process of HTML compilation is halted due to the unexpected presence of the forbidden 'null' data type, despite the fact that null cannot actually be a valid value in

Encountering an issue with my HTML code, where the compiler stops at: Type 'CustomItem[] | null | undefined' is not compatible with type 'CustomItem[] | undefined'. Type 'null' cannot be assigned to type 'CustomItem[] ...

What might be causing my action function to be triggered during the rendering process?

While working on creating a basic card view in material UI, I encountered an issue where the functions for adding and deleting items seem to be triggered multiple times upon rendering. I am aware that a common reason for this could be using action={myFunc ...

Managing multiple asynchronous requests through Observables in web development

I am working on an Angular2 website that sends multiple ajax requests using Json Web Tokens for authorization when it is initialized Here are two examples: public getUser(): Observable<User> { // Code block to get user data } public getFriends ...

Tips for populating class attributes from an Angular model

Suppose there is a Class Vehicle with the following properties: public id: number; public modelId: number; public modelName: string; Now consider we have an object that looks like this {id: 1, modelId: 1, modelName: "4"} What is the best way to assign e ...

Determining a value that increases to yield a fresh sum

I'm currently developing a character generator that determines your score based on the experience points you allocate to it. The scoring system is such that 1 XP gives you a score of 1, 3 XP gives you a score of 2, 6 XP gives you a score of 3, 10 XP g ...

Is there a method to incorporate lists of varying types in a single v-for loop without causing any issues with type validations?

My current component is designed to display two different datasets, each with their own unique nature of data: state.articleTypeList: string[] state.renderPriceClassNameList: {[key: string]: string[]} To render both datasets within a single v-for componen ...

Show Timing on the Y-Axis - Bubble Graph

Recently, I stumbled upon the Bubble Chart feature in ng2-charts. I am trying to display data based on time on the Y-axis and values on the X-axis. My dataset consists of x:[10,35,60], y:["7.00 AM"], with r having the same value as x. However, the sample d ...

Angular device redirection allows you to automatically redirect users based on the device

Currently in my Angular project, I am attempting to dynamically redirect users based on their device type. For example, if the user is on a Web platform, they will be redirected to www.web.com. If they are on an Android device, they should go to www.androi ...

Is there a way to inform TypeScript that the process is defined rather than undefined?

When I execute the code line below: internalWhiteList = process.env.INTERNAL_IP_WHITELIST.split( ',' ) An error pops up indicating, Object is possibly undefined. The env variables are injected into process.env through the utilization of the mod ...

How can I implement a redirect back to the previous query page post-authentication in Next.js 13?

To enhance security, whenever a user tries to access a protected route, I plan to automatically redirect them to the login page. Once they successfully log in, they will be redirected back to the original protected route they were trying to access. When w ...

Implementing Firebase-triggered Push Notifications

Right now, I am working on an app that is built using IONIC 2 and Firebase. In my app, there is a main collection and I am curious to know if it’s doable to send push notifications to all users whenever a new item is added to the Firebase collection. I ...

Using React MUI Select in combination with react-hook-form does not seem to be compatible with Cypress testing

Within my React application, I have implemented a form that includes a dropdown select. Depending on the option selected from the dropdown, different input fields are rendered. const [templateType, setTemplateType] = useState(""); const { regi ...

Retrieve a specific nested key using its name

I am working with the following structure: const config = { modules: [ { debug: true }, { test: false } ] } My goal is to create a function that can provide the status of a specific module. For example: getStatus("debug") While I can access the array ...

Harness the power of TypeScript in a single test file with jest's expect.extend() method

This question is similar to Can you limit the scope of a TypeScript global type? but it presents a slightly different scenario that requires clarification (although an answer to this would be greatly appreciated as well). In my Jest setup, I am attempting ...

Executing functions in TypeScript

I am facing an issue while trying to call a function through the click event in my template. The error message I receive is "get is not a function". Can someone help me identify where the problem lies? This is my template: <button class="btn btn-prima ...