Make sure a Typescript array contains a particular value

Currently, I am in the process of developing a dropdown-style component where the value and options are separate props. My goal is to incorporate Typescript to ensure that the value remains a valid option. Although I could perform this validation at runtime, I believe it should be achievable within TS.

Do you think this is feasible?

interface Props<N extends number> {
    count: N,
    options: Array<N | number> // Tuples aren't suitable as the length can vary
}

const Component = <N extends number>({count, options} : Props<N>) => {
  // While we could do a runtime check to validate `count` against `options`, it would be ideal to handle this earlier if possible
}

Component({count: 5, options: [1,2,3]}) // Ideally, this should return an error

Answer №1

The main concept here is to deduce the specific types of count and options and assign them to the generic types N and O. While it's straightforward for N, determining the type for O requires indicating to the compiler that we want a tuple type of number literals, not just an array of numbers like number[]. This can be achieved by enclosing O in a variadic tuple type represented as [...O].

To enforce validation, a conditional type is used to verify if N belongs to O[number]. If it doesn't belong, the conditional resolves to never, resulting in an error since nothing can be assigned to never.

interface Props<N extends number, O extends readonly number[]> {
  count: N;
  options: N extends O[number] ? readonly [...O] : never;
}
const Component = <N extends number, O extends readonly number[]>({
  count,
  options,
}: Props<N, O>) => {};

This approach works well when the array provided as options is a tuple type.

Component({ count: 5, options: [1, 2, 3] }); // error

Component({ count: 5, options: [1, 2, 3, 5] }); // ok

Component({ count: 5, options: [] as number[] }); 
// ok, all elements in options are numbers and 5 does extend number :/

If options happens to be an array type, with its elements being of type number, then the fact that 5 extends number ultimately satisfies the type checking requirements.


Playground

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

What is the reason behind localStorage.getItem consistently returning a string value?

Something strange is happening. In the lib.dom.d.ts file, the type for localstorage.getItem shows as 'string | null', but in my app it always returns a string. Why is this discrepancy occurring? ...

Error in JavaScript: A surprise anonymous System.register call occurred

Within Visual Studio 2015, there exists a TypeScript project featuring two distinct TypeScript files: foo.ts export class Foo { bar(): string { return "hello"; } } app.ts /// <reference path="foo.ts"/> import {Foo} from './f ...

Unable to extract the 'data' property from an undefined source in React, causing an error

I encountered this error message: TypeError: Cannot destructure property 'data' of '(intermediate value)' as it is undefined. export const getServerSideProps: GetServerSideProps = async () => { // categories const { data: categor ...

Is it possible to set up VS Code's code completion feature to automatically accept punctuation suggestions?

For all the C# devs transitioning to TypeScript in VS Code, this question is directed at you. I was captivated by the code completion feature in VS C#. To paint a clearer picture, let's say I'm trying to write: console.log('hello') W ...

Tips for displaying field options after typing parentheses in TypeScript in Visual Studio Code

Whenever the letter "b" is typed, the suggestion of "bar" appears. However, I would prefer if the suggestions show up immediately after typing the brackets. https://i.stack.imgur.com/OFTO4.png ...

What is the best way to pass a string value instead of an event in Multiselect Material UI?

Greetings, currently utilizing Material UI multi select within a React TypeScript setup. In order to modify the multi select value in the child component, I am passing an event from the parent component. Here is the code for the parent component - import ...

How can TypeScript objects be serialized?

Is there a reliable method for preserving type information during JSON serialization/deserialization of Typescript objects? The straightforward JSON.parse(JSON.stringify) approach has proven to have several limitations. Are there more effective ad-hoc sol ...

The Angular project was functioning properly when tested locally, but encountered an error in the Quill Editor during the building process

I have encountered an issue when deploying my Angular 8 + Quill project. Everything works fine locally with 'ng serve', but upon deployment, I am facing the following error. Despite trying various solutions like updating Angular or deleting &apos ...

The payload from the Axios POST request is failing to reach its destination endpoint

I have two Express servers up and running - a gateway and an authentication service. I am facing an issue where the payload I set in the body of a request from my gateway to the authentication server never seems to arrive, despite there being no apparent C ...

Retrieving the output from a nested scope within a function

I have a scenario where I am working with a function that has a nested "then" function containing a return statement. My goal is to combine this inner return data with the outer return data. Below is the code snippet: public async getAllWidgets(): Promis ...

Typescript's intriguing concept of objects containing arrays inside other objects

I have a structure similar to this and I am trying to create definitions for types/interfaces, but I am facing issues in making it work correctly. layoutsSet: { 1: { "lg": [ { i: "1", x: 0, ...

The power of absolute paths in React Native 0.72 with TypeScript

Hi everyone! I'm currently having some difficulty setting absolute paths in react native. I tried using babel-plugin-module-resolver, as well as configuring 'tsconfig.json' and 'babel.config.js' as shown below. Interestingly, VS Co ...

The onChange event does not work as expected for Select controls

I am facing an issue with my common useForm.tsx file when handling the onChange event for select controls. The error message I encounter is displayed below. Does anyone have any suggestions on how to resolve this? Error: Type '(e: ChangeEvent<HTM ...

Step-by-step guide on setting up pnpm directly, without the need to first

Here I am, faced with a brand new Windows 10 installation - only VS Code is installed and nothing more: Can pnpm be installed and used without the need for npm? Is this action beneficial or detrimental? Consideration: typescript ...

Invoke a function within the <img> tag to specify the source path

I have been attempting to achieve something similar to the following: <img id="icon" class="cercle icon" src="getIcon({{item.status}})" alt=""> This is my function: getIcon(status){ switch (status) { case 'Ongoing': ret ...

Utilizing References in React Components

One of the challenges I am facing involves a Container that needs references to some of its child components: const Container = () => { const blocks: HTMLDivElement[] = []; return ( <div> <Navigation currentBlock={currentBlock} ...

"Encountered an issue with Next-Auth session returning as undefined in getServerSideProps using NextJS version 13.2

When inspecting the code below, session is found to be undefined upon logging from the client side after being transferred from getServerSideProps. import { getServerSession } from 'next-auth/next'; import { authOptions } from './api/auth/[. ...

React / NextJS: Repeating Audiowave Component

I am currently developing a chat application in NextJS that includes text-to-speech functionality. To visualize the audio playback waveform, I have integrated a third-party library called wavesurfer.js Though the audio implementation is functioning proper ...

Issue 2339: Dealing with || and Union Types

I've encountered an interesting issue while working with TypeScript and JavaScript. I created a code snippet that runs perfectly in JavaScript but throws a syntax error in TypeScript. You can check it out in action at this TypeScript Sandbox. Essenti ...

Angular - Dropdown menu fails to display options

I encountered an issue with the JSON response from my Angular-12 API endpoint: { "message": "vehicle Model Detail.", "error": false, "code": 200, "results": { "vehiclemakes": [{ ...