Universal function for selecting object properties

I've recently delved into TypeScript coding and have run into a puzzling issue that has me stumped.

Take a look at the code snippet below:

interface testInterface {
  a: string;
  b: number;
  c?: number;
}

const testObject: testInterface = {
  a: "1",
  b: 2,
};

function selectorFunction<GenericKey extends keyof testInterface>(
  key: GenericKey
): Required<testInterface>[keyof testInterface] {
  if (testObject[key]) return testObject[key];
  throw new Error("Error");
}

To give you some context on what I'm aiming for: the selectorFunction is designed to fetch a value from testObject, based on the key it receives, while ensuring the correct data type. This is why the key property's type is set as generic.

Everything seems to work fine by itself, but things get complicated when optional properties are introduced, causing a conflict with the method's required return type to prevent undefined values.

In theory, it should be straightforward—just add an 'if' check to verify the property's existence, right? Despite attempting this fix, TypeScript continues to flag the following error:

Type 'string | number | undefined' is not assignable to type 'string | number'.
    Type 'undefined' is not assignable to type 'string | number'.
      Type 'testInterface[GenericKey]' is not assignable to type 'number'.
        Type 'string | number | undefined' is not assignable to type 'number'.
          Type 'undefined' is not assignable to type 'number'.ts(2322)

Answer â„–1

The code snippet below provides the functionality you are looking for. It also ensures that the return type is never when an error key is inputted. (Playground link)

interface testInterface {
    a: "a"
    b: "b"
    c?: "c"
}


const testObject: testInterface = {
    a: "a",
    b: "b",
}


type RequiredKeys<T> = {
    [k in keyof T]-?: undefined extends T[k] ? never : k
}[keyof T]


type GetSafely<T, K extends keyof T> =
    K extends RequiredKeys<T>
        ? T[K]
        : never


// Type examples:
    // ReqK will be 'a' | 'b'
    type ReqK = RequiredKeys<testInterface>
    // A will be 'a'
    type A = GetSafely<testInterface, "a">
    // B will be 'b'
    type B = GetSafely<testInterface, "b">
    // C will be 'never'
    type C = GetSafely<testInterface, "c">


const getSafely = <T extends {}>(obj: T) =>
    <K extends keyof T>(key: K): GetSafely<T, K> => {
        if (obj[key] !== undefined) {
            return obj[key] as GetSafely<T, K>
        }

        throw new Error("Error");
    }


const selectorFunction = getSafely(testObject);

    const a = selectorFunction("a")
    const b = selectorFunction("b")
    const c = selectorFunction("c")

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 React component fails to render when clicking on a Material-UI MenuItem

In my code, there is a simple mui Menu, where a MenuItem should trigger the rendering of another React component. The issue I am facing is that the Menu is being rendered in a separate file, which contains the definitions for the close and handleClick func ...

Guide to making a Typescript interface by combining elements from two separate interfaces without utilizing inheritance

Programming Language: Typescript I am looking to combine the properties of two interfaces as the value of an indexable-type within a third interface. Interface 1: export interface Employee { id: string name: string } Interface 2: export interfa ...

Guide to accessing and modifying attributes of Ionic components in TypeScript file

I am curious about how to manipulate the properties or attributes of an Ionic component from a TypeScript file. For example, if I have an input component on my HTML page: <ion-item> <ion-input type="text" [(ngModel)]="testText"></ion ...

Utilizing ResolveComponentFactory() with a String Key: A Step-by-Step Guide

My goal: I want to find a way to use something similar to the "resolveComponentFactory()", but with a 'string' identifier to obtain Component Factories. Once I have them, I plan to utilize the "createComponent(Factory)" method. Check out this P ...

"Typescript with React and Material-UI Table - A seamless user experience with no errors

I have been working on incorporating the "material-table" library into my TypeScript and React project, but I am facing an issue where the page appears blank without any compiling errors. Environment configuration: npm: 6.11.3 nodejs: 10.17.0 typescript: ...

Tips for refreshing a React component using incremental changes retrieved from an API

I am developing a unique React application using Next.js and TypeScript, with an api-backed data set in one component that needs to be cached indefinitely. Unlike traditional examples I have found online, my component must: Fetch only the most recent 100 ...

Remove an element from an array within objects

Need help with removing specific items from an array within objects? If you want to delete all hobbies related to dancing, you may consider using the splice method const people = [{ id: 1, documents: [{ ...

Angular: accomplish cascading requests to achieve desired outcomes

While exploring Angular rxjs operators, I came across a scenario where I need to send requests to the server that depend on each other. Currently, I have a modal window open and during the ngOnInit lifecycle hook, multiple requests are being sent, some of ...

Troubleshooting: Vue and TypeScript Components Not Communicating

Vue is still fairly new to me and I'm struggling with this issue. Despite following code examples, my implementation doesn't seem to be working correctly. The component I defined looks like this: <template> <div class="row"> ...

Ensure that missing types are included in a union type following a boolean evaluation

When working with typescript, the following code will be typed correctly: let v: number | null | undefined; if(v === null || v === undefined) return; // v is now recognized as a `number` const v2 = v + 2; However, if we decide to streamline this process ...

What is the reason that the command `npx create-react-app my-app --typescript` is not providing me with the expected TypeScript files?

I used the command npx create-react-app my-app --typescript to create my React project, but it seems like I still ended up with the default JavaScript boilerplate files. I was expecting to see files with a .tsx or .ts extension and use import * from as R ...

Using create-react-app with TypeScript for server-side rendering

My current project is built with create-react-app using typescript (tsx files). I'm now interested in implementing SSR for the project, but I'm not exactly sure where to begin. In the past, I've successfully implemented SSR with typescript ...

Guide on importing an ES6 package into an Express Typescript Project that is being utilized by a Vite React package

My goal is to efficiently share zod models and JS functions between the backend (Express & TS) and frontend (Vite React) using a shared library stored on a gcloud npm repository. Although the shared library works flawlessly on the frontend, I continue to e ...

Update an API call to switch from promises to observables, implementing axios

Recently, I have been experimenting with using rxjs for API requests in a React application and this is the approach that I have come up with. What are your thoughts on this method? Are there any best practices that you would recommend following? If you ...

When attempting to send a token from an account to a marketplace in ERC721, the transfer caller must either be the owner

Currently, I am in the process of transferring my NFT to a marketplace pragma solidity ^0.8.7; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import & ...

Expanding material UI theme choices through module augmentation is currently ineffective with TypeText

For those experiencing the issue, a codesandbox has been provided for convenience. Click here to access the codesandbox. Curiously, the TypeText feature is not functioning properly while the SimplePaletteColorOptions is working as expected. Despite being ...

Regular pattern with Kubernetes cluster endpoint utilizing either IP address or fully qualified domain name

In my Angular/typescript project, I am working on building a regex for a cluster endpoint that includes an IP address or hostname (FQDN) in a URL format. For instance: Example 1 - 10.210.163.246/k8s/clusters/c-m-vftt4j5q Example 2 - fg380g9-32-vip3-ocs.s ...

Enhancing the default functionality of React.FC within Next.js

Currently, I am working on a tutorial in Nextjs that employs the code snippet below in JavaScript. However, I am planning to transition it to TypeScript. Since I am relatively new to TypeScript, I have attempted various solutions from different sources but ...

Creating a custom autocomplete search using Angular's pipes and input

Trying to implement an autocomplete input feature for any field value, I decided to create a custom pipe for this purpose. One challenge I'm facing is how to connect the component displaying my JSON data with the component housing the autocomplete in ...

Error Message: Module not found while using Node Express with TypeScriptIssue: A

I have set up a straightforward node express app using TypeScript. My goal is to implement an errorMiddleware in the index.ts file. As I try to start the server, I encounter the following error: at Module.require (node:internal/modules/cjs/loader:100 ...