Filtering Typescript by property values of an interface that match its own values

Looking to extract specific types based on a given label

Take a look at the code snippets below:

interface TypeWithLabel {
    label: string;
    list: string;
}

interface A extends TypeWithLabel{
    label: 'a';
    list: '1' | '2' | '3';
}

interface B extends TypeWithLabel {
    label: 'b';
    list: '4' | '5' | '6';
}

type TypeProperty<T, U extends keyof T> = T[U];

function ab<T extends TypeWithLabel, U = TypeProperty<T, 'label'>>(
    label: U,
    item: TypeProperty<T, 'list'>
) {

}

// retrieve only type A with label:'a'
// and provide options '1' | '2' | '3' for item
ab<A | B>('a', '1'); // correct
ab<A | B>('a', '4'); // error

// obtain only type B with label:'b'
// and display choices '4' | '5' | '6' for item
ab<A | B>('b', '4'); // correct
ab<A | B>('b', '1'); // error

Is there an alternative method to filter these interfaces? I considered reusing generics, but label must be provided as a string value in the function.

Answer №1

It's unclear if I've grasped your intention accurately - in case you wish for the function ab to be limited to either

A</​code> or <code>B</​code>, then your generic type parameter must also reflect this criterion. You should modify your code as follows:</p>

<pre><code>// given A, restrict item to '1' | '2' | '3'
ab<A>("a", "1"); // ok
ab<A>("a", "4"); // error (ok)

// given A, restrict item to '4' | '5' | '6'
ab<B>("b", "4"); // ok
ab<B>("b", "1"); // error (ok)

Playground

The above code has a minor drawback: the generic type parameter needs to be manually set. If

U = TypeProperty<T, 'label'>
is no longer able to provide a default type one day,
U</​code> will need to be included in every part of the code involving <code>ab</​code> and cannot be automatically inferred.</p>

<p>An alternative approach is to establish a <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#keyof-and-lookup-types" rel="nofollow noreferrer">lookup type</​a> called <code>LabelToList</​code>. This method is beneficial when you have only a few interfaces like <code>A</​code> and <code>B</​code> and numerous <code>ab</​code> calls. You can avoid manual generic type parameters by structuring your example as shown below:</p>

<pre><code>type LabelToList = {
  a: A;
  b: B;
};

function ab<K extends keyof LabelToList>(
  label: K,
  item: LabelToList[K]["list"]
) {}

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

Deep Dive into TypeScript String Literal Types

Trying to find a solution for implementing TSDocs with a string literal type declaration in TypeScript. For instance: type InputType = /** Comment should also appear for num1 */ 'num1' | /** Would like the TSDoc to be visible for num2 as well ...

What causes a discrepancy between a local npm package and the repository even when they both appear to be the same version?

After updating Angular from 8.2.4 to 9.1.6 and Typescript from 3.4 to 3.8.3 using ng update @angular/cli @angular/core I encountered issues with some module imports that are now breaking. Downgrading to Typescript 3.7 works, but I require 3.8 for a speci ...

What is the best way to display multiple HTML files using React?

Looking to develop a web application using React that consists of multiple HTML pages. For instance, login.html and index.html have been created and linked to URIs through the backend - resulting in localhost:8080/login and localhost:8080/index. However, R ...

Creating and incorporating a generator function within an interface and class: A step-by-step guide

In vanilla JavaScript, the code would look something like this: class Powers { *[Symbol.iterator]() { for(let i = 0; i < 10; i++) yield { i, pow: Math.pow(i, i) } return null; } } This can then be utilized in the following manner: co ...

Encountering issues with accessing a variable before its initialization in the getServerSideProps function in

Currently, I am working on setting up Firebase and configuring the APIs and functions to retrieve necessary data in my firebase.tsx file. Afterwards, I import them into my pages/index.tsx file but I am encountering an issue where I cannot access exports af ...

Utilizing TypeScript to export a class constructor as a named function

Imagine you have this custom class: export class PerformActionClass<TEntity> { constructor(entity: TEntity) { } } You can use it in your code like this: new PerformActionClass<Person>(myPersonObject); However, you may want a more co ...

Storing the typeof result in a variable no longer aids TypeScript in type inference

Looking at the code snippet below: export const func = (foo?: number) => { const isNumber = typeof foo === 'number'; return isNumber ? Math.max(foo, 0) : 0; }; A problem arises when TypeScript complains that you cannot apply undefined to ...

Configuring Stylelint in a NextJS project using Emotionjs

I recently encountered an issue while trying to integrate Stylelint into a new NextJS Typescript project with EmotionJS. Many rules were not working in my styles files, and the only error I could identify was Unknown word CssSyntaxError. This particular U ...

Creating a versatile TypeScript interface that can accurately represent a wide range of types, interfaces, and objects whilst imposing restrictions on the allowable value types within

I am looking to define a versatile TypeScript interface that can accommodate any type, interface, or object while imposing restrictions on the types of values it contains. Let me introduce MyInterface, which includes properties fooIProp and barIProp stori ...

Exploring alternative applications of defineModel in Vue 3.4 beyond just handling inputs

The examples provided for defineModel in the Vue documentation primarily focus on data inputs. I was curious if this functionality could be utilized in different contexts, potentially eliminating the need for the somewhat cumbersome props/emit approach to ...

What is the best way to save an array of objects from an Axios response into a React State using TypeScript?

Apologies in advance, as I am working on a professional project and cannot provide specific details. Therefore, I need to describe the situation without revealing actual terms. I am making a GET request to an API that responds in the following format: [0: ...

Exporting the default value from a TypeScript declaration file module

Imagine having a declaration file called foo.d.ts: declare namespace foo { interface Bar { (): void; } } declare var foo: foo.Bar; export default foo; Upon compilation: import Foo from './foo'; Foo(); The result is: "use strict"; va ...

Create an alternate name for a specific type of key within a nested record

There are three simple types available: const structureTypes = z.enum(["atom","molecule"]) const atomTypes = z.enum(["oxygen","hydrogen"]) const moleculeTypes = z.enum(["water","ammonia"]) The goal is to define a type for a cache where the keys correspond ...

Creating a way for a Node and React application to share classes

I am in the process of developing a Node and React application, both implemented using TypeScript. The directory structure of my project is illustrated below: https://i.sstatic.net/914A1.png My query: Given that I am utilizing the same programming langu ...

Convert the date into a string format instead of a UTC string representation

I am currently working on a node.js project using TypeScript. In this project, I have a Slot class defined as follows: export class Slot { startTime: Date; constructor(_startTime: Date){ this.startTime = _startTime } } // Within a controller method ...

What is the method for extracting search parameters as an object from a URL that includes a hash symbol?

Currently, I am dealing with a URL structured in the following format: https://my-app.com/my-route/someOtherRoute#register?param1="122"&param2="333" While I am familiar with fetching query strings from a standard URL, I am struggli ...

Encountering a TypeScript issue with bracket notation in template literals

I am encountering an issue with my object named endpoints that contains various methods: const endpoints = { async getProfilePhoto(photoFile: File) { return await updateProfilePhotoTask.perform(photoFile); }, }; To access these methods, I am using ...

Retrieve type definitions for function parameters from an immutable array containing multiple arrays

My current challenge involves implementing a function similar to Jest's test.each iterator: // with "as const" forEach([ [ 1, 2, 3 ], [ "a", "b", "c" ], ] as const, (first, second, third) => { // ...

Steps to disable TypeScript error messages for unused variables

I encountered an issue in my Angular CLI that says: jest.config.js is part of the TypeScript compilation but it's unused. Add only entry points to the 'files' or 'include' properties in your tsconfig. Additionally, I have a few o ...

Getting the most out of TypeScript Enum in Angular 6

I have a situation where I am storing the numeric value of an enum in my database and then displaying it in another part of the UI. Now, I need to retrieve the string value linked with that numeric value from the enum in a separate Angular component. Here ...