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

"Upon invoking the services provider in Ionic 2, an unexpected undefined value was

I encountered an issue while setting a value in the constructor of my page's constructor class. I made a call to the provider to fetch data. Within the service call, I was able to retrieve the data successfully. However, when I tried to access my vari ...

React - The `component` prop you have supplied to ButtonBase is not valid. Please ensure that the children prop is properly displayed within this customized component

I am attempting to use custom SVG icons in place of the default icons from Material UI's Pagination component (V4). However, I keep encountering this console error: Material-UI: The component prop provided to ButtonBase is invalid. Please ensure tha ...

Is it possible for me to define TypeScript interfaces to be used in vanilla JavaScript projects within VSCode?

While using the MS VisualCode editor, I am attempting to implement type checking in my Javascript code. I want to maintain the flexibility of Javascript while also benefiting from type checking interfaces and data structures. Based on the vscode documenta ...

Looping through an array using NgFor within an object

I've been working on pulling data from an API and displaying it on a webpage. Here is the JSON structure: {page: 1, results: Array(20), total_pages: 832, total_results: 16629} page: 1 results: Array(20) 0: adult: false backdrop_path: "/xDMIl84 ...

I'm puzzled by how my observable seems to be activating on its own without

Sorry if this is a silly question. I am looking at the following code snippet: ngOnInit(): void { let data$ = new Observable((observer: Observer<string>) => { observer.next('message 1'); }); data$.subscribe( ...

Only map property type when the type is a union type

My goal is to create a mapping between the keys of an object type and another object, following these rules: Each key should be from the original type If the value's type is a union type, it should have { enum: Array } If the value's type is not ...

What can be done to prevent the angular material select from overflowing the screen?

I have integrated an Angular Material Select component into my application, which can be found here: https://material.angular.io/components/select/overview. The issue I am facing is that when the select element is positioned near the bottom of the screen a ...

Navigating an array using ngFor and encountering an error message saying, "Identifier not specified"

While using ngFor to iterate through an array, I encountered the following error message: "Identifier 'expenseitem' is not defined. The component declaration, template variable declarations, and element references do not contain such a memb ...

Using an aria-label attribute on an <option> tag within a dropdown menu may result in a DAP violation

Currently, I am conducting accessibility testing for an Angular project at my workplace. Our team relies on the JAWS screen reader and a helpful plugin that detects UI issues and highlights them as violations. Unfortunately, I've come across an issue ...

Is the user's permission to access the Clipboard being granted?

Is there a way to verify if the user has allowed clipboard read permission using JavaScript? I want to retrieve a boolean value that reflects the current status of clipboard permissions. ...

How to utilize Enzyme to call a React prop in TypeScript

I'm currently in the process of converting my Jest tests from Enzyme to TypeScript, and I've come across a specific case that I'm unsure how to resolve. Essentially, I'm attempting to invoke a function passed as a prop to a sub-componen ...

Angular Pagination: Present a collection of pages formatted to the size of A4 paper

Currently, I am working on implementing pagination using NgbdPaginationBasic in my app.module.ts file. import { NgbdPaginationBasic } from './pagination-basic'; My goal is to create a series of A4 size pages with a visible Header and Footer onl ...

Tips on optimizing NextJS for proper integration with fetch requests and headers functionality

I'm currently working on a NextJS project and following the official tutorials. The tutorials demonstrate how to retrieve data from an API using an API-Key for authorization. However, I've run into a TypeScript compilation error: TS2769: No ove ...

What is the best way to arrange items by utilizing the Array index in JavaScript?

Currently, I am attempting to make the elements within this angular component cascade upon loading. The goal is to have them appear in a specific layout as shown in the accompanying image. I'm seeking guidance on how to write a function in the TypeSc ...

What is the process for creating static pages that can access local data within a NextJS 13 application?

I recently completed a blog tutorial and I must say, it works like a charm. It's able to generate dynamic pages from .md blog posts stored locally, creating a beautiful output. However, I've hit a roadblock while attempting what seems like a sim ...

Replace a portion of text with a RxJS countdown timer

I am currently working on integrating a countdown timer using rxjs in my angular 12 project. Here is what I have in my typescript file: let timeLeft$ = interval(1000).pipe( map(x => this.calcTimeDiff(orderCutOffTime)), shareReplay(1) ); The calcTim ...

When attempting to inject a provider from the same module, the dependencies cannot be resolved

Bug Report Current Issue Encountering an error when trying to instantiate the PaymentProcessorModule: Error: Nest cannot resolve dependencies of the PaymentProcessor (?, PaymentsService, ProcessingService). Please ensure that the TransactionsService argum ...

Is there a way for me to steer clear of having to rely on the Elvis Operator?

Throughout my journey building my Angular 2 website, I've found the Elvis Operator to be a crucial element that makes everything possible. It seems like every task I undertake involves mastering how to apply it correctly in every instance where data i ...

What is the process for choosing nested colors from a theme in Material UI?

I have a question regarding how to select a nested style from my theme when creating a Button. Below is the snippet of code that illustrates my dilemma: const buttonStyle: SxProps<Theme> = { '&:hover': { backgroundColor: 'bac ...

Maintain synchrony of the state with swiftly unfolding occurrences

I developed a custom hook to keep track of a state variable that increments based on the number of socket events received. However, when I tested by sending 10 simultaneous events, the total value of the state variable ended up being 6, 7, or 8 instead of ...