Creating a secure 'select' function in TypeScript that ensures type safety

lodash offers the pick function which can be used like this:

var object = { 'a': 1, 'b': '2', 'c': 3 };
 
_.pick(object, ['a', 'c']);
// => { 'a': 1, 'c': 3 }

I am interested in creating a type-safe version of this function using typescript.

The desired usage should look like this:

pick(object, "a", "b")

The main objective is to ensure type safety while using this function.

Is it feasible to achieve this goal?

Answer №1

It seems like the solution you're looking for could involve utilizing the Pick type. How about trying out this implementation?

function select<T, K extends keyof T>(source: T, ...keys: K[]): Pick<T, K> {
  const result: any = {};
  keys.forEach(key => {
    result[key] = source[key];
  })
  return result;
}

const obj = {a: 1, b: '2', c: 3}
const selectedValues = select(obj, 'b', 'c');

selectedValues.a; // not accessible
selectedValues.b  // string
selectedValues.c  // number

Answer №2

Utilizing Object.fromEntries (es2019) in a function:

function selectKeys<T extends object, K extends keyof T> (source: T, ...keysToSelect: K[]): Pick<T, K> {
  const entries = keysToSelect.map(key => ([key, source[key]]));
  return Object.fromEntries(entries);
}

Answer №3

Here is my solution using the Object.assign() method:

function pickKeys<T, K extends keyof T>(objectToPickFrom: T, keysToPick: K[]): Pick<T, K> {
  return Object.assign(
    {},
    ...keysToPick.map(key => {
      if (objectToPickFrom && Object.prototype.hasOwnProperty.call(objectToPickFrom, key)) {
        return { [key]: objectToPickFrom[key] };
      }
    })
  );
};

Answer №4

The type definitions for lodash utilize the Pick method to automatically pass along the properties, saving you from having to define them yourself. Simply add them to your project by running either npm i --save-dev @types/lodash or yarn add -D @types/lodash.

Answer №5

After reviewing Ethan.Roday's response, I decided to make a few modifications. I utilized the Array.reduce method and eliminated the use of the any type.

function extractKeys<T, K extends keyof T>(objectToExtractFrom: T, keysToExtract: K[]) {
    return keysToExtract.reduce((accumulator, currentValue) => {
        return (accumulator[currentValue] = objectToExtractFrom[currentValue]), accumulator;
    }, {} as Pick<T, K>);
}

Answer №6

Here is my modified version, building upon @Bayu Karnia's solution:

function selectKeys<T extends Record<string | number | symbol, T>, K extends keyof T>(
  dataObject: T,
  selectedKeys: K[]
): Pick<T, K> {
  return Object.assign(
    {},
    ...selectedKeys.map((key: K) => {
      return { [key]: dataObject[key] };
    })
  );
}

Answer №7

It seems like I successfully switched arguments and used curry, resulting in satisfactory type outcomes. I would greatly appreciate it if someone could provide an explanation:

const pick = <T, K extends keyof T>(keys: (keyof T)[]) => <R extends T>(obj: R) => keys.reduce<Pick<R, K>>((acc, key) => {
    (acc as T)[key] = obj[key]
    return acc;
}, {} as Pick<R, K>)

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

reconfigure components by resetting settings on a different component

In the interface, I have a section that displays text along with a unique component titled FilterCriteriaList. This component includes custom buttons that alter their color when clicked. My goal is to reset the settings in the FilterCriteriaList component ...

Is it possible for input properties of array type to change on multiple components in Angular 9?

Encountering an interesting issue that I need clarification on. Recently, I developed a compact Angular application to demonstrate the problem at hand. The puzzling situation arises when passing an Array (any[] or Object[]) as an @Input property to a chil ...

Skipping emission during the parsing of TypeScript configuration files

Encountering an issue with the node-config library while using typescript. The structure of my config folder is depicted here: https://i.sstatic.net/BKBgv.png After running tsc and attempting to launch my app from its entry point (app.js), a error ...

Enhancing Forms with Redux and Styled Components

I'm currently working on developing a reusable component that involves using a redux-form <Field /> and styling it with styled-components within the component. The issue I'm facing is that none of the styles are being applied. Here is my ...

Transform JSON object to a class/interface object using Typescript

I am currently working on converting an API response into a TypeScript class or interface. The API is returning a list of objects with various properties, but I only require a few specific properties from the response object. Example of API Response: ...

What is the best way to showcase a standalone JSON object within the template?

I have a detailed component that is designed to show the 5-day forecast for a specific city. I have successfully retrieved the data using the http.get(Url) method. However, I am unsure of how to bind this JSON data to my view. I am familiar with displayi ...

Steps to generate a GoogleAppsScript.Document.Text object

I am looking to conduct unit testing on this Typescript code that has been transpiled using Clasp into Google App Script: function onLinksInText(text: GoogleAppsScript.Document.Text, onLink: OnLinkCallback) { const iterator = new TextIterator(text, on ...

What is the best way to retrieve the previous URL in Angular after the current URL has been refreshed or changed

Imagine being on the current URL of http://localhost:4200/#/transactions/overview/5?tab=2 and then navigating to http://localhost:4200/#/deals/detail/ If I refresh the deals/detail page, I want to return to the previous URL which could be something like h ...

Error encountered with Angular version 11.2.6 or Typescript indicating TS2345 issue

Currently, I am stuck on an Angular tutorial that includes some code, but unfortunately, I am encountering an error that I haven't been able to troubleshoot. In all instances within my code where dish or getDish are present, they are stored as strings ...

Another TypeScript Novice Encounters the Error: TypeError - Trying to Assign Value to Undefined Property '3'

There seems to be an issue with the creation of the transitions Array, but I can't figure out why! The text class export enum STATE_ID { CGU, Initial, Previous, Question} export enum CHOICE_ID {CGU_accepted, CGU_not_accepted} export class STATE_MAC ...

Creating dynamic checkboxes in Angular4 and binding them to an array of IDs

Hey there developers, I've been encountering an issue while trying to bind my dynamically generated checkboxes to an array in my project. In my users.template.html file, I have the following code snippet: <div *ngFor="let r of roles" class="checkb ...

I am looking to make changes to a user's profile

My goal is to only update the fields that I have specified, leaving other data unchanged. However, in my current situation, when I pass the key to be changed, all other fields are set to null. import userModel from '../../models/usermodel' impor ...

Best practices for setting up PDAs in the Solana Anchor framework

Trying to create a basic Solana Program using Rust/Anchor that involves a PDA is causing a CPI error upon invocation, even though there doesn't appear to be any CPI happening (possibly due to the PDA account initialization). Below is the Program code ...

Is it necessary to use ReplaySubject after using location.back() in Angular 6 to avoid requesting data multiple times?

I'm currently utilizing a BehaviorSubject in my service to retrieve data from the BackEnd, which I subscribe to in my mainComponent using the async pipe. However, whenever I navigate to another subComponent and then return to my mainComponent by clic ...

Setting the default selected row to the first row in ag-Grid (Angular)

Is there a way to automatically select the first row in ag-grid when using it with Angular? If you're curious, here's some code that may help: https://stackblitz.com/edit/ag-grid-angular-hello-world-xabqct?file=src/app/app.component.ts I'm ...

React TypeScript: Handling OnChange Events for Different Input Types

I am confronted with multiple input fields: <label> <span className="codes__input-label">Count</span> <input type="number" value={this.state.count} onChange={this.onInputChange} /> </label> ...

Oops! A mistake was made by passing an incorrect argument to a color function. Make sure to provide a string representation of a color as the argument next time

Encountering an issue with a button react component utilizing the opacify function from the Polished Library The styling is done using styled-components along with a theme passed through ThemeProvider. Upon testing the code, an error is thrown. Also, the ...

NestJS Ensures Type Safety for Mongoose Models, but Model Functions Expecting Incorrect Types (Any)

Shema Interfaces export interface MyCat { name: string; color: string; } export type Cat = MyCat & Document; export const CatSchema = new Schema({ name: { type: String, required: true, }, color: { type: String, required: tr ...

Leverage TypeScript Enum along with PropTypes to declare the properties of a React component

Upon having the Component and utilizing a TypeScript Interface for defining its props: interface Props { headerType: DROPDOWN_MENU_TYPE, //DROPDOWN_MENU_TYPE is enum headerContent: SVGClass isReverse: boolean; }; const MyComp: React.FunctionC ...

Creating an Angular service that checks if data is available in local storage before calling an API method can be achieved by implementing a

I am currently working on developing an Angular service that can seamlessly switch between making actual API calls and utilizing local storage within a single method invocation. component.ts this.userService.getAllUsers().subscribe(data => { conso ...