Ensure that the function parameter only accepts keys that are present in the specified object

I have an object with specific types for its values:

type Type = { [key: string]: ValueType }

const variable: Type = {
    key1: valueType,
    key2: valueType,
    key3: valueType,
}

Now, I need a function called func that should only accept keys from variable:

func('key1')     // OK
func('key2')     // OK
func('key3')     // OK
func('keyother') // Error
func(3)          // Error

To achieve this, I created a type for the func as follows:

type FuncType = (param: keyof typeof variable) => any
const func: FuncType = ...

However, there is a problem. I can only enforce one of the following:

  • Ensuring correct typing for the values of variable

or

  • Enforcing the correct typing for the param in func to accept only keys from variable

I'm unable to tackle both of these issues simultaneously.

  • If I focus on typing the values of variable, then the param in func ends up being of type string, which allows passing any string to func call, leading to incorrect behavior
  • If I prioritize typing for the param in func, it restricts to only valid keys but then allows anything as the value for variable

One potential solution could involve predefining a list of keys ([key1, key2, ...]) in another type. However, managing two identical lists is not ideal. How can I address both concerns without resorting to this approach?

Typescript playground provides further insight into this issue, along with explanatory comments.

Answer №1

To ensure type validation, it is recommended to utilize a helper function that serves the purpose of validating the type.

const makeType = <T extends Type = Type>(obj: T) => obj

const variable = makeType({
    key1: 0,
    key2: 0,
    key3: 0,
})

Playground

UPDATE: TypeScript 4.9 will introduce satisfies feature

Announcing TypeScript 4.9 Beta

const variable = {
    key1: valueType,
    key2: valueType,
    key3: valueType,
} satisfies Record<string, ValueType>

Answer №2

I believe BorisTB's solution is highly effective, as it is both intuitive and direct. It seems to meet the criteria outlined in your question.

If you're experiencing issues with the solution not working as expected, it appears that when both problems occur simultaneously (invalid key value in variable, invalid keyname in func), errors for both are not being displayed concurrently. Here is an alternate approach:

Try it out here

Essentially, this method involves conducting an additional check on variable after it has been declared with its const type.

const variable = { 
    key1: 0,
    key2: 0,
    key3: 'wrong type value',
} as const;
variable as Type;

This extra validation simply compiles to just variable on its own, minimizing any disruption. You will receive detailed error messages when either an invalid value in variable or an invalid argument in func occurs, ensuring errors for both scenarios are highlighted correctly.

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

Is it possible to modify the default behavior of a sensitive region within a button?

I created a calculator application in React and overall, it's working fine, however... I've noticed that when I hold a click longer, it only registers as a click if the mouse was pressed down and released on the button itself. Although I unders ...

Tips for loading nested JSON data into an Angular Material dropdown list

My task involves extracting data from a JSON object and displaying the difficultyLevel. Despite several attempts, I have been unable to achieve the desired outcome. What changes should be made to the HTML file? const ELEMENT_DATA: data = { questions ...

Parsing JSON objects with identifiers into TypeScript is a common task in web development

I possess a vast JSON object structured like so: { "item1": { "key1": "val1", "key2": "val2", "key3": [ "val4", "val5", ] }, { "item2": { "key1": "val1", "ke ...

Having trouble with obtaining real-time text translation using ngx translate/core in Angular 2 with Typescript

Issue : I am facing a challenge with fetching dynamic text from a JSON file and translating it using the translate.get() method in Angular2. this.translate.get('keyInJson').subscribe(res => { this.valueFromJson = res; /* cre ...

The route will be altered once the route transition or animation has been initiated

As route change triggers an animation, I have a black div that slides from the bottom to the top of the page during transition. The animation of the sliding div is working correctly. However, the issue arises when the route changes simultaneously with the ...

Can a circular dependency be tolerated when a type declaration file brings in an enum from the implementation?

Let's say you have an implementation file called module.ts and a type declaration file named module.d.ts. // module.ts import type ConfigI from 'module.d.ts'; export enum ConfigType { Simple, Complex } function performTask(config: Conf ...

Tips on deleting a nested JSON key?

Here is an example of my JSON structure: var data = [{ "ID" : 3, "discRec" : "Some sample record", "Tasks" : [{ "ID" : 7, ...

What is the correct way to add properties to an interface in TypeScript?

I have experience with styled-components "themes" and how they work by defining custom theme properties for TypeScript autocompletion within styled components. The process involves extending the DefaultTheme interface with our custom theme properties like ...

A tutorial on implementing a "Back to Top" button that appears dynamically while scrolling in Angular

I've developed a scroll-to-top feature for my Angular project, but I'm facing an issue. The scroll icon appears immediately upon page load instead of only showing after the user scrolls down. Any ideas or suggestions on how to achieve this? Here ...

What is the implication when Typescript indicates that there is no overlap between the types 'a' and 'b'?

let choice = Math.random() < 0.5 ? "a" : "b"; if (choice !== "a") { // ... } else if (choice === "b") { This situation will always be false because the values 'a' and 'b' are completely disti ...

"Design a function that generates a return type based on the input array

Created a function similar to this one // window.location.search = "?id1=123&id2=ABC&id3=456" const { id1, id2, id3 } = readArgsFromURL("id1", {name: "id2", required: false}, {name: "id3", required: true}) ...

Enhance your Next.js routing by appending to a slug/url using the <Link> component

In my Next.js project, I have organized my files in a folder-based structure like this: /dashboard/[appid]/users/[userid]/user_info.tsx When using href={"user_info"} with the built-in Next.js component on a user page, I expect the URL to dynamic ...

Interacting Between Module Components in Angular 2

I have a situation where I have one component that needs to pass data to another component located in a different module. The app.component acts as the parent of these child modules. However, they are only connected through routing, so they are not technic ...

The SonarTsPlugin report is coming back clean with no issues found in the Typescript files

In my current project, I am attempting to analyze an Angular application using SonarQube. This particular project consists of a mix of JavaScript and TypeScript files. During the Sonar analysis process, I have noticed that while issues are being generated ...

Ways to decrease the size of this item while maintaining its child components?

Here is an object that I am working with: { "name": "A", "children": [ { "name": "B", "open": false, "registry": true, "children": [ { ...

Retrieving array values to be used as Typescript data types

Is there a method to transform array values into strings? Here is what I came up with: class A { public keys = ['name', 'age'] } type ArrayKeys = P in A['keys'] // 'name' or 'age' Any suggestions on ...

In order to retrieve specific object attributes using the unique identifier

I am currently managing 2 API's referred to as teachers and sessions. The contents of the teachers JSON file are: [ { "teacherName": "Binky Alderwick", "id": "01" }, { "teacherName": "Basilio Gregg", ...

Using Vue.js - error occurs when trying to push an object using the push method

I encountered an issue while trying to use the push() method to add data to an object: Uncaught (in promise) TypeError: this.message.push is not a function The scenario involves receiving data from an API call and needing to append it to an object. var ...

What is the best way to start a class instance within a stateless function component in React?

When following a stateful pattern, my usual approach is to initialize a helper class in the constructor and consume its methods in component lifecycle methods, as shown in the example below: class StatefulComponent extends Component { constructor(props) ...

How to deliver various static files in NestJS using different paths and prefixes?

I've set up static file serving for developer documentation using the following code: app.useStaticAssets(docsLocation, { prefix: "/docs/" }) Now I have another directory with more static content that I want to serve. Is it possible to serve from ...