Make sure the object has a key that changes dynamically

To ensure that only existing keys are accessed on a specific object, I have implemented the following code:

function prop<O, K extends keyof O>(key: K, obj: O) {
    return obj[key];
}

This validation method functions correctly when utilized in the following manner:

const obj = { foo: 'bar' };
prop('foo', obj); // valid
prop('bar', obj); // invalid

However, my goal is to restructure the code so that it functions like this instead:

const obj = { foo: 'bar' };
prop('foo')(obj); // should be allowed
prop('bar')(obj); // should trigger an error

Initially, I attempted to adjust the function as follows:

function prop<O, K extends keyof O>(key: K) {
    return function inner(obj: O) {
        return obj[key];
    }
}

Unfortunately, this approach did not work and led to the following error:

Argument of type '"foo"' is not assignable to the parameter of type 'never'.

The reasoning behind this error makes sense to me as the object is not accessible during key validation.

As a result, my aim is to switch the validation logic from "verify that the key exists in the object" to "confirm that the object contains the key" immediately after the object is passed into the second function. If the key is not found, a type validation error should occur with no other restrictions at that specific point.

While it seems achievable using TypeScript, I am yet to discover a method to accomplish this with a fully dynamic key and object, where the only requirement for the object is the presence of the specified key.

Answer №1

In the scenario where O is not yet established, it cannot be utilized as a parameter in the initial function call since there is no reference point for it. Alternatively, you could manually define it but this is not recommended.

Another approach is to specify the O parameter in the second function. During the first call, K (acting as a generic key) will be specified. On the subsequent call, the O will be designated with the requirement that it must contain a key K with any type.

function prop<K extends keyof any>(key: K) {
    return function inner<O extends Record<K, any>>(obj: O) : O[K]{
        return obj[key];
    }
}

const obj = { foo: 'bar' };
prop('foo')(obj); // should work fine, returns string
prop('bar')(obj); // will result in an error

Answer №2

If you enjoy explicitly specifying the type, then you can use the following method:

function getProperty<T>(property: keyof T) {
    return function getter(object: T) {
        return object[property];
    }
}

getProperty<{ name: string }>('name')({ name: 'John'}) // works fine
getProperty<{ name: string }>('name')({ nickname: 'Johnny'}) // results in an error

Answer №3

Start by placing the type parameter at the beginning:

const findProperty = <T>(property: keyof T) =>
  (source: T) =>
    source[property];

To ensure maximum type safety, specify the type parameter when invoking findProperty:

const findProperty = <T, Key extends keyof T = keyof T>(property: Key) =>
  (source: T): T[Key] =>
    source[property];

findProperty<typeof data>('name')(data); // $ExpectType string
findProperty<typeof data>('age')(data); // $ExpectError

Answer №4

Are you okay with this?

function checkProperty<T extends object>(object: T, propertyName: string): boolean {
        return (object as any)[propertyName] !== undefined;
    }

You can also utilize Object.keys()

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

Detecting if a string is in sentence or title case with a typeguard

When setting the sameSite property of a cookie, it must be either Strict, Lax, or None. However, the package I'm using uses lowercase values for this attribute. Therefore, I need to adjust the first letter of the string: let sentenceCaseSameSite: &quo ...

Exploring Transformation in Angular

I am looking to enhance my understanding of how ChangeDetection works, and I have a query in this regard. When using changeDetection: ChangeDetectionStrategy.OnPush, do I also need to check if currentValue exists in the ngOnChanges lifecycle hook, or is i ...

Collective picture in the exhibit

I recently created a photo gallery that showcases various images sorted by categories. In this setup, I have one object containing both images and their respective categories, and another object solely dedicated to storing the categories. The challenge I ...

Issue when calling .create() method on Mongoose schema: "this expression is not callable" error in TypeScript

Encountering an error with the .create method on a mongoose model in Next JS while making a call in an API route. The get request is functioning properly... The structure: pages>API>task.tsx import dbConnect from "../../util/dbconnect"; im ...

What is the best way to save a Map for future use in different components?

Let's say I define an enum like this: export enum SomeEnum { SomeLongName = 1, AnotherName = 2 } Within my display components, I'm utilizing an enum map to translate the enum values into strings for presentation on the web app: enumMap = new Map ...

Exploring the Concept of Extending Generic Constraints in TypeScript

I want to create a versatile function that can handle sub-types of a base class and return a promise that resolves to an instance of the specified class. The code snippet below demonstrates my objective: class foo {} class bar extends foo {} const someBar ...

The mat-selection-list fails to display within the mat-autocomplete menu

When developing a mat-autocomplete component to allow for multiple selections, I opted to utilize a mat-selection-list. This choice was made in order to take advantage of built-in features like checkboxes. However, despite initializing the 'chartList ...

Learn how to mock asynchronous calls in JavaScript unit testing using Jest

I recently transitioned from Java to TypeScript and am trying to find the equivalent of java junit(Mockito) in TypeScript. In junit, we can define the behavior of dependencies and return responses based on test case demands. Is there a similar way to do t ...

Guide to verifying the existence of a specific object mapping in JavaScript

I am currently working with an object mapping called res.payload.data[0].tnxResponse. I need to verify that the res object contains a payload property which in turn has a data property and so on. I attempted to do this using the following code, but it resu ...

A function in Typescript that can handle dynamic keys and values using generics

function convertArrayToObject<T>(array: T[], key: keyof T): Record<string, T> { return array.reduce( (accumulator: Record<string, T>, currentValue: T) => Object.assign(accumulator, { [String(currentValue[key])]: cur ...

What is the process for setting a Type to a prop in React?

I have a main component: // DashboardComponent.tsx const DashboardComponent = () => { const {loading, error, data} = useQuery(resolvers.ReturnAllMovies); if (loading) return <p>loading</p>; if (error) return <p>Error! ${error.m ...

Employing the filter or find technique to extract an element contained within a JSON data structure

Is it possible to retrieve one of these items using the filter or find method to search for a match within the fiberAgrupations array? I attempted the following: const landlineRate = this.monolineJsonRates[0].cambioCaudal.getAll() .filter(landlinedRat ...

collapsible menu with expand/collapse button

When I click on the menu, such as the administration section, step1 Next, I proceed to click on the toggle button step2 After clicking, the toggle button becomes activated step3 Then, I click on the button toggle once more step4 My issue arises whe ...

What is the best way to transmit a JSON object to REST services using Angular?

Whenever I attempt to send the JSON object to REST services, I encounter an error that looks like this: http://localhost:8080/api/v1/cardLimit 400 (Bad Request); JSON Object Example: public class GameLimit implements Serializable { private stati ...

The Chrome browser's console is malfunctioning and displaying values as undefined

When using the Chrome console, the values are displaying as undefined, but in the sources tab, the values are visible. https://i.sstatic.net/6aHvi.png Despite obtaining values for this.listdealfunding here, in the console, it appears as undefined. https ...

Converting an array of objects into a TypeScript dictionary with IDs as the key mapping

Is there a way to provide type hints for better autocompletion when accessing keys like dictionary.Germany from the following data and types? type Entry = { tld: string; name: string; population: number; }; const data: Entry[] = [ {tld: 'de&a ...

Familial Connection (TYPESCRIPT)

Is there a way to set the state in ISetOpen based on the type of modal in ISetOpen? For example: If ISetOpen.modal is 'payModal': Set ISetOpen.state to IPayModal If ISetOpen.modal is 'deleteModal': Set ISetOpen.state to IDeleteModal ...

Converting base64 dataUrls into images using typescript

When using ng2-image cropper, it does not accept the "src" attribute and instead requires the "image" attribute. As a result, if a dataUrl is provided, the image will not display in the cropper. I am utilizing the camera to capture an image and obtaining ...

TypeScript Generic Extended React Component

I am trying to enhance the React Component class with my own custom class. export class CustomReactComponent<P,S> extends React.Component<P,S> { public doSomeStuff() { alert("Custom React Component"); } } export class MyCompon ...

Using Conditional Checks in Angular 2 for Form Validations

I am looking to create a universal template for both guest and customer registration forms, with varying validations. Imagine we have a Register form for Guests where firstName is required <form #f="ngForm" novalidate (ngSubmit)="save()"> ...