Select a specific type of child

One of my preferences:

type selectedType = { 
  name: string, 
  category: string,
  details: { 
    color: string,
    material: string,
    size: string,
  },
}

How do I select details.material only? Here is what I expect as output:

type selectedTypePick = { 
  details: { 
    material: string,
  },
}

I prefer not to manually write code like:

type selectedTypePick = {
  details: Pick<selectedType['details'], 'material'>;
};

Answer №1

To implement a nested Pick within a Mapped Type, follow this structure:

type CustomType = { 
  a: string, 
  b: string,
  c: { 
    x: string,
    y: string,
    z: string,
  },
}

type CustomTypePick = {
  [K in keyof Pick<CustomType, "c">]: Pick<CustomType["c"], "y">
};

TypeScript Playground


Pro tip: Start type names with a capital letter for consistency.

Answer №2

Hello there, I am in charge of maintaining the ts-essentials project. Within our toolkit, we have a handy utility type known as DeepPick that could be of assistance in your specific situation.

I want to emphasize that utilizing this approach would be most advantageous when a more generic solution is needed, particularly if you find yourself needing it in multiple places with varying levels. Otherwise, feel free to disregard this and opt for the approach involving Pick and mapped types.

  • If you want to experiment with the ts-essentials utility type in the TypeScript Playground, visit - https://tsplay.dev/NdyA6m
  • To view the complete extracted utility type in the TypeScript Playground (including an example at the end), follow this link - https://tsplay.dev/mZy49N
  • For a simplified version of the extracted utility type (without autocomplete and fewer edge cases) in the TypeScript Playground, click here - https://tsplay.dev/N7Q14W

You can make use of this type to specifically retrieve the values you require:

type newType = { 
  a: string, 
  b: string,
  c: { 
    x: string,
    y: string,
    z: string,
  },
}

type OnlyCY = DeepPick<
  // ^? { c: { y: string } }
  newType,
  {
    c: {
      y: never
    }
  }
>;

The simplified solution appears concise and elegant:

type Primitive = string | number | boolean | bigint | symbol | undefined | null;

type Builtin = Primitive | Function | Date | Error | RegExp;

type AnyRecord = Record<string, any>;

export type DeepPick<Type, Filter> = Type extends Builtin
  ? Type
  : Filter extends AnyRecord
  ? {
      // iterate over keys of Type, which keeps the information about keys: optional, required or readonly
      [Key in keyof Type as Key extends keyof Filter ? Key : never]: Filter[Key & keyof Filter] extends true
        ? Type[Key]
        : Key extends keyof Filter
        ? DeepPick<Type[Key], Filter[Key]>
        : never;
    }
  : never;

If you have any questions, feel free to reach out to me. Happy coding!

Answer №3

Here is a helpful code snippet for achieving the desired result:

type ExtractY<T> = {
  [K in keyof T]: K extends 'c' ? Extract<T[K], 'y'> : T[K];
};

type MyType = { 
  a: string, 
  b: string, 
  c: { 
    x: string,
    y: string,
    z: string,
  },
};

type MyTypeExtracted = ExtractY<MyType>;

By using MyTypeExtracted, you will obtain the following output:

type MyTypeExtracted = { 
  a: string, 
  b: string, 
  c: { 
    y: string,
  },
};

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

Steps for converting an Array of tuples into a Union of Tuples

I am attempting to develop a custom type that, when given an array of tuples as input, will generate the union of each index within the tuple. This may not be the most accurate terminology, but I hope you understand what I mean. const entries = [["name", ...

Angular error TS2322 arises when attempting to assign a type of 'Observable<{}>' with the share() operator

Currently diving into Angular 5, I've been exploring the Observable/Observer pattern to facilitate event sharing and data changes among subscribers. Below is a snippet of the code in question: ... @Injectable() export class NidoService { ... eve ...

Updating the displayed data of an angular2-highcharts chart

I am facing an issue with rendering an empty chart initially and then updating it with data. The charts are rendered when the component is initialized and added through a list of chart options. Although the empty chart is successfully rendered, I am strugg ...

Angular2's ErrorHandler can cause code to malfunction when an error occurs

import { Injectable, ErrorHandler, Inject, Injector } from '@angular/core'; import { MessengerService } from '../services'; import { MessageTypeEnum } from '../../shared'; @Injectable() export class AppErrorHandler extends Er ...

Is there a solution available for the error message that reads: "TypeError: Cannot set value to a read-only property 'map' of object '#<QueryCursor>'"?

Everything was running smoothly in my local environment, but once I deployed it on a Digital Ocean Kubernetes server, an error popped up. Any assistance would be greatly appreciated. https://i.stack.imgur.com/VxIXr.png ...

I'm looking to learn how to implement the delete method in an API using TypeScript. Can anyone help me out

I am seeking guidance on utilizing 'axios' within 'nuxt.js'. I have experimented with sample data, and I am particularly interested in learning how to utilize the 'axios' method within 'nuxt.js' using TypeScript. T ...

Tips for establishing optimal parameters for an object's dynamic property

I am working with an array of objects: export const inputsArray: InputAttributes[] = [ { label: 'Name', type: 'text', name: 'name', required: true }, { label: 'User name ...

Perform an action after the Ngx Bootstrap modal has been hidden

My modal features a login button: <button type="button" (click)="save()" class="btn btn-primary"> login </button> Upon clicking the button, my desired outcome is to: first hide the modal, and second navigate to another route. However, ...

"Setting up a schema in TypeORM when connecting to an Oracle database: A step-by-step guide

As a newcomer to TypeORM, I'm using Oracle DB with Node.js in the backend. Successfully connecting the database with TypeORM using createConnection(), but struggling to specify the schema during connection creation. One workaround is adding the schem ...

The Route.ts file does not export any HTTP methods

Encountering an error while trying to migrate code from Next JS 12 with pages router in Javascript to Next JS 13 with TypeScript. ⨯ Detected default export in 'vibe\src\app\api\auth[...nextauth]\route.ts'. Export a name ...

Unit testing the error function within the subscribe method in Angular

I've been working on a unit test for the subscribe call, but I'm struggling to cover the error handling aspect of the subscribe method. The handleError function deals with statusCode=403 errors and other status codes. Any assistance would be grea ...

There is an issue with the property 'updateModf' in the constructor as it does not have an initializer and is not definitely assigned

When working with an angular reactive form, I encountered an issue. After declaring a variable with the type FormGroup like this: updateModf:FormGroup; , the IDE displayed an error message: Property 'updateModf' has no initializer and is not def ...

Toggle Button in Angular upon Form Changes

I am currently working on a bug that involves preventing users from saving data if they have not entered any information in the form. The form structure is as follows: private buildAddressPopupForm() { this.form = this.fb.group({ roles: [''], ...

How can one properly conduct a health check on a Twilio connection using TypeScript?

How can I create an endpoint in TypeScript to verify if the Twilio connection is properly established? What would be the proper method to perform this check? Below is a snippet of my current code: private twilioClient: Twilio; ... async checkTwilio() { ...

Tips for implementing a coupon code feature on Stripe checkout in an Angular 8+ application

I need to implement an input option for entering coupons in the Stripe payment gateway when the handler is open on the front end. I currently have a Stripe window open and would like to provide users with a way to enter coupon codes. // Function to Load ...

Inject the data within Observable<Object> into Observable<Array>

I'm faced with a situation where I have two distinct API endpoints. One endpoint returns a single Card object, while the other endpoint returns an Array of Card objects. My goal is to retrieve the first Card from the single Card endpoint and place it ...

Angular: Converting JSON responses from HttpClient requests into class instances

I am facing an issue with the following code: public fetchResults(searchTerm: string): Observable<Array<SearchResult>> { let params = new HttpParams().set('searchTerm', searchTerm); return this.http .get<Array< ...

Angular error: Unable to access the 'toLowerCase' property of an undefined value

I've been working on creating my own custom filter pipe by following the instructions in this video tutorial, but I encountered an error message stating, "Angular, TypeError: Cannot read property 'toLowerCase' of undefined". I have already i ...

The response from my reducer was a resounding "never," causing selectors to be unable to accurately detect the state

Currently utilizing the most recent version of react. I am attempting to retrieve the state of the current screen shot, but encountering an error indicating that the type is an empty object and the reducer is "never". I am unable to detect the state at all ...

Angular component classes now use the updated RXJS 6.X syntax, rendering the previously used observable deprecated

Here is the component method I am using: if (id !== undefined && id != null && id !== 0) { this.dataService.getTransactionById(id).subscribe( (tr: ITransactionResponse) => { ...