A Typescript function that safely extracts object properties using currying

My goal is to add typings for the prop function. It follows a curried pattern where the key is passed first and the object is passed last.

I attempted an approach where I partially apply it to a key, then try to restrict it to an object containing that property.

This is how I tried to implement it:

const prop = (key: string) =>
  <K, T extends { [key: string]: K }>(obj: T): K =>
  obj[key]

Unfortunately, this approach doesn't seem to work as expected. For instance, when running this code snippet on TypeScript Playground:

const getFoo = prop('foo')
getFoo({ fooo: 42 })

The error message states:

Error: type '{ fooo: number }' is not assignable to '{ foo: number }'

Vexpected behavior should be an explicit failure instead of failing silently. Also, I expect the type inference to correctly determine the property type in an object. Thus, the following code should fail as intended:

const someNumber: number = prop('foo')({ 'foo': 'abc' })

The error displayed should look like this:

Error: type 'string' is not assignable to 'number'.

This scenario works as designed. However, if I remove the type annotation from someNumber, the type remains unknown:

const someNumber = prop('foo')({ 'foo': 'abc' })

Is there a way to satisfy all these conditions? I've also considered approaching it "the other way around," by specifying the type of the object we will be working with first and using <T, K extends keyof T>, but this would require users to provide type parameters each time...

Answer №1

Give this a shot:

const selectProp = <Key extends string>(key: Key) =>
  <T extends Record<Key, any>>(object: T): T[Key] =>
  object[key];

const getBar = selectProp('bar')
const output: number = getBar({ bar: 99 })

Answer №2

I successfully crafted a solution utilizing the concept of mapped types:

const prop = <K extends string>(key: K) =>
  <T extends { [k in K]: T[K] }>(obj: T): T[K] => obj[key];

Explore this further on the 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

Convert a generic observable list to a generic list

Can an array containing [Observable<string>, Observable<number>] be converted to [string, number] using generics? function example(obs: Observable<any>[]): any[] { } Intended Outcome: example(of(''), of(0)) // should return [st ...

Access the most up-to-date information through the API URL

Objective: Whenever the 'Test' Button is clicked, new data must be fetched from the backend using the API link and displayed on the modal form. Issue: If text in the input box is changed or deleted, then the modal is closed and the 'Tes ...

Accessing the name and value of an enum in Typescript

One particular enum is causing some confusion: export enum myEnum { name1 = 'my name', name2 = 'my other name', name3 = 'other' } An object of myEnum has been created: const x = myEnum.name1; console.log(x) // prints ...

How can I incorporate dynamic fields into a Typescript type/interface?

In my Typescript interface, I have a predefined set of fields like this: export interface Data { date_created: string; stamp: string; } let myData: Data; But now I need to incorporate "dynamic" fields that can be determined only at runtime. This me ...

Monitor constantly to determine if an element is within the visible portion of the screen

For a thorough understanding of my query, I feel the need to delve deeper. While I am well-versed in solving this issue with vanilla Javascript that is compatible with typescript, my struggle lies in figuring out how to invoke this function throughout th ...

The code is throwing an error: Unable to access the 'grower' property as it is undefined

I'm facing an issue with a button that triggers the function 'SaveNewOpportunity' in my component file. When I click the button, I encounter the following error: ERROR TypeError: Cannot read property 'grower' of undefined Here is ...

Issue with capturing events in Angular through emitting events

Apologies for my inexperience with Angular (V12), if I am not explaining my issue clearly. I am facing a problem with the $Event not capturing the custom object data emitted from another component. Upon setting up the function in the parent component, I en ...

Tips for utilizing buttons with the antd framework in Visual Studio Code

When using the Button and Input components from antd in vscode, I encountered an error specifically with the Button component and I am curious to understand why it is happening. Interestingly, when I tried using the Input component, it did not show any er ...

Exploring the functionality of CanDeactiveGuard and ModalDialogService through unit testing

In my application, the CanDeactiveGuard is functioning properly. During unit testing, I encountered an issue with one test where I intended to use callThrough to invoke the openConfirmDialog() method within the Guard. This method triggers the Modal Dialog ...

Tips for incorporating attributes into a customized Material-UI props component using TypeScript in React

I'm interested in using material-ui with react and typescript. I want to pass properties to the components, but I'm having trouble figuring out how to do it. Currently, I'm working with the react-typescript example from the material-UI repos ...

What is the best way to transform a string into emojis using TypeScript or JavaScript?

Looking to convert emoji from string in typescript to display emoji in html. Here is a snippet of the Typescript file: export class Example { emoji:any; function(){ this.emoji = ":joy:" } } In an HTML file, I would like it to dis ...

Swapping JSON: A Quick Guide

When my Angular code loads, a list of buttons (button 1, button 2, button 3, etc.) is displayed. Upon clicking any button, the console shows J-SON with varying values. Two additional buttons are present on the page for moving up and down. My dilemma arise ...

Error TS2305: The module "@prisma/client" does not have an export named "User"

Setting up a Gitlab CI for my nestjs project using prisma has been my current challenge. I keep encountering this error when running the pipeline: see image here This is what my .gitlab-ci.yml looks like: image: node:latest stages: - build build: st ...

Angular index.html file can include a conditional script

I am currently working on an Angular project, where the index.html serves as the main entry point for the application, just like in any other Angular project. This file contains important links and configurations. Within the HTML code snippet below, you w ...

What is the procedure for accessing a namespace when declaring it globally?

Website Project Background Currently, I am working on a simple website where users can update their pictures. To achieve this functionality, I am utilizing the Multer library along with Express in Typescript. Encountered Issue I am facing a challenge re ...

Encountering issues with TypeScript class

I am facing an issue with transpiling the following TypeScript class: class DataService { styles: Object[]; selectedStyle: Object; selectedChildStyle: Object; constructor() { this.styles = [{ "name": " ...

Original: Generic for type guard functionRewritten: Universal

I have successfully created a function that filters a list of two types into two separate lists of unique type using hardcoded types: interface TypeA { kind: 'typeA'; } interface TypeB { kind: 'typeB'; } filterMixedList(mixedList$: ...

What are the circumstances under which JavaScript GCP libraries return null values?

My current project involves working with GCP and Firebase using typescript. I have been utilizing the provided libraries, specifically version 8 of Firebase, and have encountered some unexpected behavior. For instance (firebase, ver. 8.10.1) import 'f ...

Do TypeScript project references provide value when noEmit is used?

To enhance the speed of my editor interaction and reduce the time taken by tsc to run on my TypeScript code, I am considering implementing project references. Many teams have reported substantial performance improvements after incorporating project referen ...

What is the solution to the error message "Unable to assign property of undefined"?

I am currently working on an angular countdown timer and encountering a TypeError when attempting to access a variable from another component. I am struggling to identify the root cause of this issue. Here is the video tutorial that I am using as a referen ...