Can a standard tuple be matched with its corresponding key?

This code snippet showcases a function that can recognize that the key "banana" cannot have the value "red":

type Fruits = {
  banana: 'yellow' | 'green'
  strawberry: 'red'
}

const fruit = <K extends keyof Fruits>(module: K, action: Fruits[K]) => true

fruit('banana', 'red') // error: not assignable to parameter of type '"yellow" | "green"

Is there a way to achieve similar functionality using tuples?

type FruitTuple<K extends keyof Fruits> = [K, Fruits[K]]

const c: FruitTuple<keyof Fruits> = ['banana', 'red'] // no error

What about using template literals?

type FruitTemplate<K extends keyof Fruits> = `${K}.${Fruits[K]}`

const c: FruitTemplate<keyof Fruits> = 'banana.red' // no error

Can this also be done with objects?

type Fruit<K extends keyof Fruits> = {
  name: K
  color: Fruits[K]
}

const d: Fruit<keyof Fruits> = { name: 'banana', color: 'red' } // no error

Answer №1

Absolutely! However, it's important to note that passing keyof Fruits into the generic won't provide enough information for TypeScript to determine exactly which fruit you are referencing. To resolve this issue, you need to explicitly specify the literal type in each of your examples for it to work correctly.


type FruitTuple<K extends keyof Fruits> = [K, Fruits[K]]

const c: FruitTuple<'banana'> = ['banana', 'red'] // error

type FruitTemplate<K extends keyof Fruits> = `${K}.${Fruits[K]}`

const d: FruitTemplate<'banana'> = 'banana.red' // error

type Fruit<K extends keyof Fruits> = {
  name: K
  color: Fruits[K]
}

const e: Fruit<'banana'> = { name: 'banana', color: 'red' } // error

This scenario showcases the effectiveness of using generics with functions, as TypeScript can automatically infer the specific type when the function is called. Conversely, directly creating values with generic tuples, template literals, or objects does not grant the same level of inference power, resulting in instances like

const c: FruitTuple<'banana'> = ['banana', 'red']
seeming redundant.

Nevertheless, you can still utilize custom tuple types or any other constructs as needed. Creating helper functions can simplify the process of instantiating desired values and types.

function makeFruitTuple<K extends keyof Fruits>(fruit: K, color: Fruits[K]): FruitTuple<K> {
    return [fruit, color];
}

const myFruitTuple1 = makeFruitTuple('banana', 'yellow'); // ok
const myFruitTuple2 = makeFruitTuple('banana', 'red'); // error

Interactive 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

Automatically injecting dependencies in Aurelia using Typescript

Recently, I started working with Typescript and Aurelia framework. Currently, I am facing an issue while trying to implement the @autoinject decorator in a VS2015 ASP.NET MVC 6 project. Below is the code snippet I am using: import {autoinject} from "aure ...

Utilizing a Function's Parameter Type in TypeScript: A Beginner's Guide

Currently, I am creating a custom method that wraps around Angular's HttpClient service. I want users to have the ability to pass in options, but I am struggling to find the proper way to reference that type in my method parameter definition. For exa ...

The type 'string' cannot be assigned to the type '"GET" | "get" | ...'

In my custom hook, I utilize the axios library for making requests: const useCustomHook = ({ endPoint = "", method = "GET", options = {} }) => { const [data, setData] = useState([]); const [request, setRequest] = useState<AxiosRequestConfig> ...

Encountering a 500 (Internal Server Error) while attempting to fetch a single document from MongoDB without utilizing the

I am currently developing my first project using the MEAN stack, and I'm facing a challenge with retrieving a single element from MongoDB. The specific page I'm working on is meant to allow users to edit an item from a list displayed on the main ...

Creating layers of object declarations

Looking for assistance on the code snippet below. type Item = { id: number; size: number; } type Example = { name: string; items: [ Item ]; } var obj: Example = { name: "test", items: [ { i ...

The data type 'T[K]' does not meet the required conditions of 'string | number | symbol'

I am currently in the process of developing a straightforward function to eliminate duplicates from an array using TypeScript. While I acknowledge that there are numerous methods to accomplish this task, my main objective is to enhance my understanding of ...

Filter array to only include the most recent items with unique names (javascript)

I'm trying to retrieve the most recent result for each unique name using javascript. Is there a straightforward way to accomplish this in javascript? This question was inspired by a similar SQL post found here: Get Latest Rates For Each Distinct Rate ...

The RxJS observable fails to initiate the subscribe function following the mergeMap operation

I am attempting to organize my dataset in my Angular application using the RxJS operators and split it into multiple streams. However, I am facing difficulties making this work properly. Inside my SignalRService, I have set up a SignalR trigger in the cons ...

Can a TypeScript-typed wrapper for localStorage be created to handle mapped return values effectively?

Is it feasible to create a TypeScript wrapper for localStorage with a schema that outlines all the possible values stored in localStorage? Specifically, I am struggling to define the return type so that it corresponds to the appropriate type specified in t ...

Error Message: Fatal error encountered - TS6046: The value provided for the '--moduleResolution' option is invalid. Valid options include: 'node', 'classic', 'node16', 'nodenext

As I develop a next.js web app with typescript and tailwind CSS, I encountered an issue. When running yarn dev in the terminal, I received this error message: FatalError: error TS6046: Argument for '--moduleResolution' option must be: 'node ...

Troubleshooting problem with Angular Click Outside Directive and unexpected extra click event issue

The challenge I'm facing involves implementing a custom Click Outside Directive for closing modal dialogs, notifications, popovers, and other 'popups' triggered by various actions. One specific issue is that when using the directive with pop ...

Issue with MUI Select custom MenuItem functionality not functioning as expected

Having an issue with MUI's MenuItem in conjunction with Select and rendering it within a separate component. Check out the codesandbox for reference. The setup is as follows: import { Select } from "@material-ui/core"; import CustomMenuIte ...

Utilize Firebase for Playwright to efficiently implement 'State Reuse' and 'Authentication Reuse'

In my testing environment, I want to eliminate the need for repeated login actions in each test run. My approach involves implementing 'Re-use state' and 'Re-use Authentication', but I've encountered a challenge with Firebase using ...

Is there a way to locate a prior version of the NPM @types package?

Currently, I am utilizing Angular version 1.4.7 and in need of a type file corresponding to this specific version. Browsing through the NPM website, I came across a type file for AngularJs listed as version 1.5.14 alpha. Is there a way to access a compreh ...

Troubleshooting SPFX and Angular: Difficulty accessing service in component.ts file

I recently developed a project using the SharePoint SPFX framework and integrated all the necessary Angular (6.0 or 7.0) TypeScript packages. While Angular seems to be functioning properly within my SPFx webpart, I encountered an issue when attempting to c ...

Transforming dynamic class based on state value from React to TypeScript

I'm trying to implement this React function in TypeScript, but I'm encountering errors. const ListItem = ({ text }) => { let [showMore, setShowMore] = useState(false); return ( <div className="item"> ...

Preventing Multiple Login Attempts in Angular.js Using Typescript

Is there a way to maintain the user login attempts limit even after page refresh? login() { /* Check if user has fewer than 5 failed login attempts */ if (this.failedAttempts < 4) { this.auth.login(this.credentials).subscribe(() => { this.rou ...

Send an API request using an Angular interceptor before making another call

Within my application, there are multiple forms that generate JSON objects with varying structures, including nested objects and arrays at different levels. These forms also support file uploads, storing URLs for downloading, names, and other information w ...

New Requirement for Angular Service: Subclass Constructor Must Be Provided or Unable to Resolve all Parameters for ClassName (?)

During a recent project, I encountered an issue while working on several services that all extend a base Service class. The base class requires a constructor parameter of HttpClient. When setting up the subclass with autocomplete, I noticed that their con ...

Angular 2: Converting JSON data into an array

I am working with JSON data that contains vendor fields and I need to extract unique vendors into an array. Can someone provide guidance on how to achieve this in an Angular2 component? Here is the sample data: [{"category": "Living Room", "vendor": "Fle ...