What is the best way to design a function that mimics the functionality of the "in" operator while also providing key suggestions

I am trying to create a function similar to the "in" operator with key suggestion in TypeScript. I am facing an issue with typing the return type as Pick<T, K> showing a warning, even though the code is working perfectly fine.

const users = {
    "Alice": {
        "id": 1,
        "name": "Alice",
        "age": 30,
        "isActive": true
    },
    ...
}

type AllKeys<T> = T extends unknown ? keyof T : never

//@ts-ignore
function hasKey<T extends object, K extends AllKeys<T>>(obj: T, key: K): obj is Pick<T, K> {
  return key in obj
}

const userKey = "Alice" as keyof typeof users
const user = users[userKey]

if ("hasSubscription" in user) {
  user.hasSubscription
}
if (hasKey(user, "isVerified")) {
  user.isVerified
}

Playground

/** Pick<T, K> is warning
 fixing or better solution
*/
//@ts-ignore
function hasKey<T extends object, K extends AllKeys<T>>(obj: T, key: K): obj is Pick<T, K> {
  return key in obj
}

Answer №1

If you're searching for a way to filter union types in TypeScript, then using the `Extract<T, U>` utility type is more suitable than the Pick<T, K> utility type:

function hasKey<T extends object, K extends AllKeys<T>>(
  obj: T, key: K
): obj is Extract<T, Record<K, any>> {
  return key in obj
}

The Pick<T, K> utility type works on a single object type T, resulting in a narrower version containing only the properties specified by K. For example,

Pick<{a: string, b: number}, “a”>
evaluates to {a: string}. This might not align with your requirements.

In contrast, the Extract<T, U> type allows you to filter a union type T based on members assignable to U. Thus,

Extract<{a: string} | {b: number}, {a: any}>
results in {a: string}. This aligns more closely with what you need.

To selectively filter union types in T according to members with a specific property at key K, each entry in

T</code can be matched against <code>Record<K, any>
using the `Record` utility type.

You can validate its functionality as follows:

if (“hasSubscription” in user) {
  user.hasSubscription // valid access
}
if (hasKey(user, “isVerified”)) {
  user.isVerified // valid access
}

Feel free to explore the code implementation in this Playground link.

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

Does the Typescript compiler sometimes skip adding braces?

I am encountering a problem with compiling a specific section of code in my Angular2 project. public reloadRecords() { let step = (this.timeInterval.max - this.timeInterval.min) / this.recordsChartSteps; let data = new Array(this.recordsChartSteps ...

An instance of an abstract class in DI, using Angular version 5

I have multiple components that require three services to be injected simultaneously with the same instance. After that, I need to create a new instance of my class for injecting the services repeatedly. My initial idea was to design an abstract class and ...

Is it possible to dynamically pass a component to a generic component in React?

Currently using Angular2+ and in need of passing a content component to a generic modal component. Which Component Should Pass the Content Component? openModal() { // open the modal component const modalRef = this.modalService.open(NgbdModalCompo ...

Modules can cause issues with Angular routing functionality

I am working on a management system that consists of multiple modules. The starting point for the application is the login-module. Upon successful login, the user is redirected to the main-module. From the main-module, users can navigate to other modules ...

Having trouble resolving modules after generating tsconfig.json?

I recently added a tsx component to my next.js 13 project following the documentation. After creating the required tsconfig.json file, I encountered module not found errors when running npm run dev: $ npm run dev > [email protected] dev > n ...

Is it possible to define TypeScript interfaces in a separate file and utilize them without the need for importing?

Currently, I find myself either declaring interfaces directly where I use them or importing them like import {ISomeInterface} from './somePlace'. Is there a way to centralize interface declarations in files like something.interface.ts and use the ...

Creating a generic that generates an object with a string and type

Is there a way to ensure that MinObj functions correctly in creating objects with the structure { 'name': string }? type MinObj<Key extends string, Type> = { [a: Key]: Type } type x = MinObj<'name', string> Link to Playgr ...

The issue arises when trying to access the 'addCase' property on the type 'WritableDraft<search>' within the builder argument of extra reducers

I am a beginner when it comes to using TypeScript with Redux Toolkit and I have encountered an issue with addCase not being available on the builder callback function in my extraReducers. I haven't been able to find a similar situation online, and I s ...

Could one potentially assign number literals to the keys of a tuple as a union?

Imagine having a tuple in TypeScript like this: type MyTuple = [string, number]; Now, the goal is to find the union of all numeric keys for this tuple, such as 0 | 1. This can be achieved using the following code snippet: type MyKeys = Exclude<keyof ...

Leveraging import and export functionality in TypeScript while utilizing RequireJS as a dependency

I am in the process of transitioning a complex JavaScript application from Backbone/Marionette to TypeScript. While making this shift, I want to explore the benefits of exporting and importing classes using files as modules. Is it necessary to incorporat ...

increase the selected date in an Angular datepicker by 10 days

I have a datepicker value in the following format: `Fri Mar 01 2021 00:00:00 GMT+0530 (India Standard Time)` My goal is to add 60 days to this date. After performing the addition, the updated value appears as: `Fri Apr 29 2021 00:00:00 GMT+0530 (India St ...

Swap out the img tags sourced from the headless cms with the Next Image component

Currently, I am developing a headless WordPress marketing/commerce application with Next.js (hosted on Vercel). My goal is to parse incoming content bodies in order to dynamically replace img tags with the Next/Image Image component. If anyone has suggesti ...

Dealing with Nested Body Payload in PATCH Requests with Constructor in DTOs in NestJS

Within my NestJS environment, I have constructed a DTO object as follows: export class Protocol { public enabled?: boolean; public allowed?: boolean; constructor(enabled: boolean, allowed: boolean) { // With a necessary constructor this.enabled = ...

Is it possible for a typed function to access object properties recursively?

Is there an efficient method in TypeScript to type a function that can recursively access object properties? The provided example delves two levels deep: function fetchNestedProperty<T, K extends keyof T>(obj: T, prop1: K, prop2: keyof T[K]) { r ...

Providing the correct context to the function in Angular's dialog data is crucial for seamless

Currently, I have a scenario where a service and a component are involved. In the service, there is an attempt to open a dialog in which a reference to a method existing in the service is passed. The code snippet below provides an example: export class So ...

Assign a value to the class attribute of the body element using ngClass

Currently, I am trying to change the value of a class based on whether a user is signed in or not. I have checked the code in both app.component.ts and login.component.ts as shown below; app.component.ts export class AppComponent { isAuthenticated:bool ...

I need to access the link_id value from this specific actionid and then execute the corresponding function within the Ionic framework

I have a JavaScript code in my TypeScript file. It retrieves the attribute from a span element when it is clicked. I want to store this attribute's value in a TypeScript variable and then call a TypeScript function. Take a look at my ngOnInit method, ...

What is the best approach to managing a 204 status in Typescript in conjunction with the Fetch API

Struggling to handle a 204 status response in my post request using fetch and typescript. I've attempted to return a promise with a null value, but it's not working as expected. postRequest = async <T>(url: string, body: any): Promise ...

The issue with loading scripts in a ReactJS NextJS app is related to the inline condition not working

I'm having trouble with an inline condition for loading scripts. The condition seems to be working because the tag is displaying text, but when it comes to scripts, it doesn't work. How can I resolve this issue? const cookie = new Cookies().get ...

Steps to transfer extra files such as config/config.yaml to the .next directory

I have the following folder structure for my NextJS project: _posts/ components/ hooks/ config/ <--- includes config.yaml file for the server pages/ public/ .env.local ... yarn build successfully copies all dependencies except for the config/ folder. ...