What is the process for creating a PickByValue data type?

The TypeScript language comes with a built-in Pick type, which is defined as follows:

type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

If you were to create a custom PickByValue type, how would you implement it to achieve the following functionality:

type Test = {
  includeMe: 'a' as 'a',
  andMe: 'a' as 'a',
  butNotMe: 'b' as 'b',
  orMe: 'b' as 'b'
};

type IncludedKeys = keyof PickByValue<Test, 'a'>;
// IncludedKeys = 'includeMe' | 'andMe'

Answer №1

If your intention is for Test to have the following structure:

type Test = {
  includeMe: 'a',
  andMe: 'a',
  butNotMe: 'b',
  orMe: 'b'
};

and you want PickByValue<T, V> to return properties that are subtypes of V (so for PickByValue<T, unknown> it should be equal to T), then you can define PickByValue like this:

type PickByValue<T, V> = Pick<T, { [K in keyof T]: T[K] extends V ? K : never }[keyof T]>
type TestA = PickByValue<Test, 'a'>; // {includeMe: "a"; andMe: "a"}
type IncludedKeys = keyof PickByValue<Test, 'a'>; // "includeMe" | "andMe"

Alternatively, if you only need the keys as in IncludedKeys, you can achieve that directly with KeysMatching<T, V>:

type KeysMatching<T, V> = {[K in keyof T]: T[K] extends V ? K : never}[keyof T];
type IncludedKeysDirect = KeysMatching<Test, 'a'> // "includeMe" | "andMe"

Link to Playground with code snippet

Answer №2

With the release of TypeScript 4.1, a new as clause has been introduced to simplify mapping:

type Test = {
  includeMe: 'a',
  andMe: 'a',
  butNotMe: 'b',
  orMe: 'b'
};

type PickByValue<T, V> = { [K in keyof T as T[K] extends V ? K : never]: T[K] };

type IncludedKeys = keyof PickByValue<Test, 'a'>;
// IncludedKeys = 'includeMe' | 'andMe'

Check it out on TypeScript 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 could be the reason for the tsc command not displaying compilation errors when compiling a particular file?

My file, titled app.ts, contains the following code snippet: interface Foo { bar:String; } const fn = (foo? :Foo) => foo.bar; When I run tsc from the root folder with strict:true in my tsconfig.json file, I receive an error message like this ...

What is the process of customizing a Button component from Ant Design using styled components and TypeScript?

I'm trying to customize a Button from Ant Design using TypeScript and styled-components to give it a personalized style. However, I haven't been successful in achieving the desired result. I have experimented with various tests but none of them ...

Exploring the process of associating a string with a specific enum value in TypeScript

One scenario is if you receive a string value from the server and have an enum type with string values defined. In TypeScript, how can you convert the string value to the enum type? export enum ToolType { ORA= 'orange', ST= 'stone' , ...

Create a chronological timeline based on data from a JSON object

Here is a JSON object generated by the backend: { "step1": { "approved": true, "approvalTime": "10-11-2021", "title": "title 1", "description": "description 1" ...

Unable to find solutions for all parameters in AnalysisComponent: ([object Object], ?, ?, [

As a newcomer to the Angular framework, I encountered an issue when adding project services. Error: Can't resolve all parameters for AnalysisComponent: ([object Object], ?, ?, [object Object], [object Object], [object Object], [object Object], [obj ...

Consolidate multiple generic items into a single entry

In my current project, I am structuring the types for a complex javascript module. One of the requirements is to handle multiple types using generics, as shown in the snippet below: export interface ModelState< FetchListPayload, FetchListR ...

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 ...

What is the best way to access all the attributes (excluding methods) of an object in a class instance?

My goal is to generate a new object type that inherits all the properties from an existing class instance. In other words, I am looking for a way to transform a class instance into a plain object. For example, consider the following scenario: ...

Error: It is not possible to assign a value to the Request property of the Object since it only has a getter method

Encountering issues while attempting to deploy my Typescript Next.js application on Vercel. The build process fails despite functioning correctly and building without errors locally. Uncertain about the root cause of the error or how to resolve it. The f ...

Material-UI chart displays only loading lines upon hovering

Currently, I am utilizing a Material UI Line chart in my NextJS 14 application to showcase some data. Although the data is being displayed properly, I have encountered an issue where the lines on the chart only render when hovered over, rather than appeari ...

Clear out chosen elements from Angular Material's mat-selection-list

Looking for a way to delete selected items from an Angular Material list, I attempted to subtract the array of selected items from the initial array (uncertain if this is the correct approach). The challenge I face is figuring out how to pass the array of ...

Attempting to search for an item by its id within a local json file using Angular

I have a local JSON file containing Kitchen types. I created the KitchenTypesService with two functions inside, GET and FIND(ID). The GET function is working fine, but the FIND function is not working and displaying an error "ERROR TypeError: Unable to lif ...

Having trouble with data types error in TypeScript while using Next.js?

I am encountering an issue with identifying the data type of the URL that I will be fetching from a REST API. To address this, I have developed a custom hook for usability in my project where I am using Next.js along with TypeScript. Below is the code sni ...

Streamlining all icons to a single downward rotation

I am currently managing a large table of "auditpoints", some of which are designated as "automated". When an auditpoint is automated, it is marked with a gear icon in the row. However, each row also receives two other icons: a pencil and a toggle button. W ...

Leverage the useRef hook with React Draggable functionality

Having recently delved into coding, I find myself navigating the world of Typescript and React for the first time. My current challenge involves creating a draggable modal in React that adjusts its boundaries upon window resize to ensure it always stays wi ...

AgGrid Encounters Difficulty in Recovering Original Grid Information

After making an initial API call, I populate the grid with data. One of the fields that is editable is the Price cell. If I edit a Price cell and then click the Restore button, the original dataset is restored. However, if I edit a Price cell again, the ...

Issue with iOS 10: Changes to class not reflected in CSS/styles

Currently, I am utilizing Ionic with Angular to develop an application for Android and iOS. Surprisingly, everything functions smoothly on Android, but there seems to be an issue with iOS. I am employing a class change on an element using ng-class. I can ...

Tips on implementing mongoose 'Query<any>' types

I have been exploring ways to incorporate a cache layer into my TypeScript project. Recently, I came across an insightful article on Medium titled How to add a Redis cache layer to Mongoose in Node.js The author demonstrates adding a caching function to m ...

What is the best way to insert CSS code into a custom Vue directive file?

I need a solution that applies a gradient background to the parent div in case an image fails to load. I've attempted to create a directive for this purpose: export default { bind(el: any, binding: any) { try { ..... ...

Personalizing the predefined title bar outline of the input text field

The outline color of the title in the input textbox appears differently in Google Chrome, and the bottom border line looks different as well. <input type="text" title="Please fill out this field."> https://i.stack.imgur.com/iJwPp.png To address th ...