What are the steps to incorporating the pick function in TypeScript?

The TypeScript documentation mentions a pick function that is declared but not implemented. In an attempt to create a simplified version, I wrote the following:

function pick<T, K extends keyof T>(obj: T, key: K): Pick<T, K> {
  return { [key]: obj[key] }
}

When testing this implementation, I encountered the error message: "TS2322: Type { [x: string]: T[K]; } is not assignable to type Pick." The issue seems to be related to key being generalized as string instead of keyof T. Is it possible to implement pick without resorting to using any or explicit casting like as Pick<T, K>? Additionally, I want to emphasize that I do not wish to utilize Partial<T> as a return type, but rather return a specific field chosen by the user.

As an alternative approach, I also attempted the following:

function pick<T, K extends keyof T>(obj: T, key: K): { [key in K]: T[K] } {
  return { [key]: obj[key] }
}

Unfortunately, this resulted in a similar error. My current TypeScript version is 4.7.4.

Answer №1

Currently, TypeScript has a limitation where a computed property key with a type that is not a single string literal type gets widened to the type string. Visit microsoft/TypeScript#13948 for more details. To work around this, you'll need to use a type assertion.


This issue hasn't been resolved yet because defining {[k]: v} as of type Record<typeof k, typeof v> doesn't work when typeof k is a union type or a generic type which might resolve to a union type. This complicates the situation as Record<typeof k, typeof v> ends up having all keys whereas {[k]: v} should have only one.

The same problem arises in the implementation of your pick() function. The return type of pick(obj, key) might not be Pick<T, K> due to possible unions in K, making it a challenging scenario to handle.

The correct approach for pick(obj, key) would involve distributing Pick<T, K> across unions in K. You can achieve this using a distributive conditional type like

K extends keyof T ? Pick<T, K> : never
or a distributive object type such as
{[P in K]-?: Pick<T, K>}[K]
.


For instance, consider the following example:

interface Foo {
    a: number,
    b: number
}
const foo: Foo = { a: 0, b: 1 }
const someKey = Math.random() < 0.5 ? "a" : "b";
// const someKey: "a" | "b"

const result = pick(foo, someKey);

In this case, we don't want result to be of type

Pick<Foo, "a" | "b"></code, which essentially just equals <code>Foo
. To address this, define pick() to return one of the distributive types mentioned earlier and utilize a type assertion accordingly:

function pick<T, K extends keyof T>(obj: T, key: K) {
    return { [key]: obj[key] } as K extends keyof T ? Pick<T, K> : never
}

With this modification, the outcome is as follows:

const result = pick(foo, someKey);
// const result: Pick<Foo, "a"> | Pick<Foo, "b">

Hence, result is either a Pick<Foo, "a"> or a Pick<Foo, "b">, satisfying the desired behavior.

Playground link to code

Answer №2

If you want to create the object and then return it, you can use a function like the one below:

function select<T, K extends keyof T>(object: T, property: K): Pick<T, K> {
  let result: any = {}  
  result[property] = object[property]

  return result
}

To see this code in action, click here.

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

The issue arises when attempting to use the search feature in Ionic because friend.toLowerCase is not a valid function

I keep encountering an error message that says "friend.toLowerCase" is not a function when I use Ionic's search function. The unique aspect of my program is that instead of just a list of JSON items, I have a list with 5 properties per item, such as f ...

The first argument passed to CollectionReference.doc() must be a string that is not empty

I'm facing an issue with my Ionic app while attempting to update records in Firebase. The error message I keep encountering has me stumped as to where I might be going wrong. Error: Uncaught (in promise): FirebaseError: [code=invalid-argument]: Functi ...

Challenges encountered when retrieving parameters from union types in TypeScript

Why can't I access attributes in union types like this? export interface ICondition { field: string operator: string value: string } export interface IConditionGroup { conditions: ICondition[] group_operator: string } function foo(item: I ...

The challenge of extending a TypeScript generic to accept an Array type with unrelated elements

I have a function that resembles the following mock: // All properties in this type are optional. interface MyType { a?: string } // The return result type of `cb` is kept as the final result type. const f = <T extends ReadonlyArray<MyType>> ...

Angular Error: Cannot call function panDelta on this.panZoomAPI

Check out my small demonstration using a stackblitz, I'm having an issue. In the setup, there's a master component with pan-zoom functionality containing a parent component with children content. The library in use is ngx-panzoom. The default c ...

When working with Typescript, you can declare an interface and split its definition across multiple files

I've been developing a software application that utilizes WebSocket with the NodeJS ws package. My networking structure revolves around a module responsible for handling message reception and transmission. Given that I'm working with TypeScript, ...

Challenges arise with data updating following a mutation in @tanstack/react-query

As I work on building an e-commerce website using React, I have a specific feature where users can add products to their favorites by clicking a button. Following this action, I aim to update the profile request to display the user's information along ...

Unable to perform navigation during page load in a React.js application

I attempted to navigate to a route that should redirect the user back to the homepage when postOperations isn't set in the localStorage. To save time, please review the code snippet focusing on the useEffect and the first component inside return(). im ...

Combining the output of two Observables through the CombineLatest method to generate a

I possess two separate collections of information: Data Model: taxControlReference [ { "providerId": "HE", "taxTables": { "STAT": [ 1 ] } }, ...

What is the best way to automatically focus on my input when the page loads?

My Angular application has a 'slider' component that loads 3 child components utilizing ng-content. The first child component contains a form, and I am trying to focus on the first field upon page load. Despite setting up ViewChild correctly to r ...

Errors are not displayed in vee-validate for objects

When utilizing [email protected] [email protected] the problem arises while attempting to validate a nested object and displaying an error. An example was created based on the documentation. However, when trying to include :has-error="Bo ...

React: Why aren't class methods always running as expected?

I created a class component that retrieves a list of applications from an external API. It then sends a separate request for each application to check its status. The fetching of the applications works well, but there is an issue with the pinging process ...

What could be causing Typescript Intellisense to not display Object extensions?

Let's take a look at this unique way to extend the Object type: interface Object { doSomething() : void; } Object.prototype.doSomething = function () { //perform some action here } With this modification, both of the following lines will c ...

react-vimeo not firing onPause and onPlay events

I am facing an issue with triggering props when playing a Vimeo video on my webpage. Here's a snippet of my code: import Vimeo from '@u-wave/react-vimeo'; const handleVimeoProgress = (data: any) => { console.log('Progress:' ...

What is the significance of parentheses when used in a type definition?

The index.d.ts file in React contains an interface definition that includes the following code snippet. Can you explain the significance of the third line shown below? (props: P & { children?: ReactNode }, context?: any): ReactElement<any> | nu ...

Tips for quietly printing a PDF document in reactjs?

const pdfURL = "anotherurl.com/document.pdf"; const handleDirectPrint = (e: React.FormEvent) => { e.preventDefault(); const newWin: Window | null = window.open(pdfURL); if (newWin) { newWin.onload = () => ...

Leveraging generics within TypeScript

I have developed a class in TypeScript that uses generics. export class ModelTransformer { static hostelTransformer: HostelTransformer; static fromAtoB(instance: T): U { if (instance instanceof HostelType) { return ModelTrans ...

Error TS2339: The 'selectpicker' property is not found on the 'JQuery<HTMLElement>' type

Recently, I integrated the amazing bootstrap-select Successfully imported bootstrap-select into my project with the following: <!-- Latest compiled and minified CSS --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstra ...

Observing changes in a parent component variable with Angular

One feature of my form is that it consists of a parent component and a child component. To disable a button within the form, I utilize a function called isDatasetFilesValid() which checks a specific variable (datasetList[i].fileValid). This variable is mo ...

Discovering all words enclosed by '#' in a string using React TypeScript

Trying to figure out how to extract words between '#' in a given string... For example: const str = `<Table striped bordered hover> <thead> <tr> <th>#project name#</th> <th>#First Name#& ...