Can the keys be extracted from the combination of multiple objects?

Basic Example

Consider this scenario

type Bar = { x: number } | { y: string } | { z: boolean };
    

Can we achieve

type KeysOfBar = 'x' | 'y' | 'z';
    

I attempted this without success

type Attempted = keyof Bar; // never

    

Check TsPlayground

Answer №1

When using something like keyof (A | B | C), only the keys that are definitely present in an object of type A | B | C will be returned. This means the key must be known to exist in all of A, B, and C, essentially resulting in:

keyof A & keyof B & keyof C
. In other words, keyof T is considered "contravariant in T". However, if there are no common keys across the union, the intersection is never.

If you want to find the set of keys that exist in at least one of the types in the union, you need to distribute the keyof operator over the union members. This can be achieved using distributive conditional types like so:

type AllKeys<T> = T extends any ? keyof T : never;

The T extends any part signals to the compiler to process operations on each union member of T separately before combining the results back into a union. This means AllKeys<A | B | C> is handled as

AllKeys<A> | AllKeys<B> | AllKeys<C>
. Let's see an example:

type KeysOfFoo = AllKeys<Foo>;
// type KeysOfFoo = "a" | "b" | "c"

It seems to work as expected! Just keep in mind the caution when using KeysOfFoo with objects of type Foo. The contravariant nature of keyof means there are potential risks, as demonstrated below:

function hmm(foo: Foo, k: AllKeys<Foo>) {
  foo[k]; // error!
  // "a" | "b" | "c"' can't be used to index type 'Foo'.
  // Property 'a' does not exist on type 'Foo'
}

Indexing into foo with k may lead to errors if the key doesn't actually exist within the object. Pay close attention to any interactions between AllKeys<Foo> and Foo. Despite the risks, there may still be valid use cases depending on your specific needs.


Access the Playground link for the code

Answer №2

Unsuccessful falls under the category of never because the type Foo cannot have any properties. It is currently structured as an intersection of 3 mutually exclusive types, resulting in no valid properties.

If you switch from using | to &, it should function correctly.

type Foo = { a: number } & { b: string } & { c: boolean }

type a = keyof Foo // 'a' | 'b' | 'c'

Try it on 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

I encountered the error message "The property you are trying to access does not exist on the type 'never'" while attempting to retrieve JSON data from the API response

Every time I attempt to access the fields in items such as id or title, an error pops up saying Property does not exist on type 'never'. Interestingly, when I log the data using console.log(response.data), everything seems to be working fine. I ...

Have there been any instances of combining AngularJS, ASP.NET-WebApi, OData, Breeze.js, and Typescript?

I am attempting to combine different technologies, but I am facing challenges as the entity framework meta-datas are not being consumed properly by breeze.js. Despite setting up all configurations, it's proving to be a bit tricky since there are no ex ...

Having difficulty loading Angular2/ Tomcat resources, specifically the JS files

I am currently in the process of deploying my Angular2 web application on a Tomcat server. After running the ng build command, I have been generating a dist folder and uploading it to my Tomcat server. However, whenever I try to run my web app, I encounte ...

Using Angular Typescript with UWP causes limitations in accessing C# WinRT component classes

Currently, I am working on a UWP application built with Angular5 and I would like to incorporate Windows Runtime Component(Universal) classes into the application to access data from a table. import { Component,OnInit } from '@angular/core'; @C ...

Update my SPFx web component to link to a CSS file instead of embedding the CSS styles directly within the component

I recently developed a web part that is reminiscent of a similar one found on GitHub @ https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-enhanced-list-formatting. This particular web part enables the embedding of custom CSS code directly in ...

The issue arises when attempting to invoke a method from a global mixin in a Vue3 TypeScript component

I've been working on this challenge for the past week, and I would appreciate any help or insights from those who may have experience in this area. Currently, I am in the process of converting vue2-based code to vue3 for a new project. Instead of usi ...

Testing Slack's Web API with Jest for mock purposes

Currently, I am working with two files. One file is where I set up a slack web API client to post a message and test it with a mocked value: main.ts: import { WebClient } from '@slack/web-api'; const slack = new WebClient(process.env.SLACK_API_K ...

Component in Angular with an empty variable in TypeScript

I'm encountering an issue on my web page where I have a loop calling a component multiple times. I successfully pass data to the component, but the problem arises when I try to display the value of an object in the component. In the component's H ...

Could someone provide a detailed explanation of exhaustMap in the context of Angular using rxjs?

import { HttpHandler, HttpInterceptor, HttpParams, HttpRequest, } from '@angular/common/http'; import { Injectable } from '@core/services/auth.service'; import { exhaustMap, take } from 'rxjs/operators'; import { Authe ...

Receiving undefined when subscribing data to an observable in Angular

Currently, I am facing an issue in my Angular project where subscribing the data to an observable is returning undefined. I have a service method in place that retrieves data from an HTTP request. public fetchData(): Observable<Data[]> { const url = ...

The dropdown navigation bar fails to close upon being clicked

I'm currently facing an issue with the navbar in my project. The bootstrap navbar doesn't close automatically after clicking on a link. I have to move my mouse away from the navbar for it to close, which is not ideal. Additionally, I'm worki ...

Contrasting expressEngine and ng2engine: An In-depth Comparison

I am currently utilizing the universal-starter framework. In regards to the file server.ts, I noticed that making the switch from import { expressEngine } from 'angular2-universal'; app.engine('.html', expressEngine); to import { n ...

Issue with Angular Datatable: Table data is only refreshed and updated after manually refreshing the page or performing a new search query

Having trouble updating Angular Datatable after selecting different data? The API response is coming in but the table data is not being updated. Can anyone suggest how to properly destroy and reinitialize the table for the next click? Below is a snippet ...

Typescript encountering difficulty in accessing an array saved in sessionStorage

Imagine you have an array stored as a string in session storage, and you need to retrieve it, add an element, and then save it back. trackNavHistory = (path: String) => { let historyArr : Array<String> = sessionStorage.getItem("navHistory ...

Creating spec.ts files for components by hand: A guide

Currently, I am facing an issue where the automatic generation of spec.ts files has been disabled by the developers when they created the components. To address this, I manually created the spec.ts files by copying over an existing one into each component, ...

Is there a memory leak causing Node.js memory growth in the (system)?

I have come across a peculiar memory leak in our live environment, where the heap continues to grow due to (system) objects. Heap snapshot Here is a memory dump showing a spike in memory usage up to 800MB: https://i.sstatic.net/vvEpA.png It seems that t ...

Application: The initialization event in the electron app is not being triggered

I am facing an issue while trying to run my electron app with TypeScript and webpack. I have a main.ts file along with the compiled main.js file. To troubleshoot, I made some edits to the main.js file to verify if the "ready" function is being called. ...

Inspecting an unspecified generic parameter for absence yields T & ({} | null)

Recently, I came across a perplexing issue while responding to this specific inquiry. It pertains to a scenario where a generic function's parameter is optional and its type involves the use of generics. Consider the following function structure: func ...

What is preventing type guarding in this particular instance for TypeScript?

Here is an example of some code I'm working on: type DataType = { name: string, age: number, } | { xy: [number, number] } function processInput(input: DataType) { if (input.name && input.age) { // Do something } e ...

The absence of a 'body' argument in the send() json() method within the Next.js API, coupled with TypeScript, raises an important argument

Currently, I have set up an API route within Next.js. Within the 'api' directory, my 'file.tsx' consists of the following code: import type { NextApiRequest, NextApiResponse } from "next"; const someFunction = (req: NextApiReq ...