Attempting to grasp the boundaries of 'T extending infer U'

I've come to understand that something like:

type CustomExample<K> = K extends (infer V) ? V : 'foo';

is actually equivalent to:

type CustomExample<K> = K extends K ? K : 'foo';

However, when the complexity increases, TypeScript throws an error:

type Options = 'text' | 'date' | 'articles' | 'parameters';

type MyCustomType<Option extends Options> =  { opt : Option };

type MyCustomUnion = Options extends (infer V) ? MyCustomType<V> : never;
// Type 'V' does not meet the requirement of 'Options'.
// Type 'V' cannot be assigned to type '"params"'.

So I'm wondering why this is incorrect: in such cases involving union distribution, the inferred V should take values like text, then date, and so forth. Therefore, what exactly does K extends (infer V) signify, and when is it appropriate to utilize it?

Answer №1

The utilization of `infer` seems to be misguided in your current approach - typically, infer is employed for "inferring" (or perhaps more aptly, resolving) types, often from generics.

In the manner you are employing it, you are crafting a type devoid of any "dynamic" elements (essentially lacking generality), signifying that it remains constant. Hence, inferring from something perennially static becomes illogical. Given that at compile time, it's already evident that Types only extends Types & '...anything else', and as you cannot specify that additional portion within your MyExperimentsUnion type, the utility of infer diminishes.

Illustrative Example

interface Action<T> {
    payload: T
}

type ExtractGeneric<T> = T extends Action<infer X> ? X : never

function retrievePayload<T extends Action<any>>(action: T): ExtractGeneric<T> {
    return action.payload;
}

const myAction = { payload: 'Test' };
const resolvedPayloadType = retrievePayload(myAction);

In the scenario mentioned above, resolvedPayloadType would yield string as the resolved type. Without using infer, you would likely need to pass that return type as a second parameter like this:

function retrieveUnextractedPayload<T extends Action<U>, U>(action: T): U {
    return action.payload;
}

Here is the playground link provided for reference.

Cheers.

Answer №2

Although this question was posted a year ago, for those who are just joining us now, here is the information you need.

I'm not sure how I overlooked this in the documentation, but since we're all in the same boat here, let's explore what's happening (starting from your code).

type Types = 'text' | 'date' | 'articles' | 'params';

type MyExperiment<Type extends Types> =  { t : Type };

// The parentheses around "infer U" can be removed as they serve no purpose here
type MyExperimentsUnion = Types extends infer U ? MyExperiment<U> : never;
// Type 'U' does not satisfy the constraint 'Types'.

In your code, you're only using the infer keyword to capture Types, but that doesn't provide TypeScript with any information about U. This might lead you to wonder why:

type foo = Types extends infer U ? U : never;
// foo will display 'text' | 'date' | 'articles' | 'params'

You might ask yourself, "Isn't U then of type

'text' | 'date' | 'articles' | 'params'
? Why can't it be assigned to MyExperiment<>?". In my opinion, the union type is resolved only at the end of the conditional statement, so it isn't technically available when assigning it as a type parameter to MyExperiment<>.

If you wish to use infer and distribute the type properly, you'll need an additional condition to constrain U at that point to ensure it's used correctly as a type parameter in MyExperiment<>.

type MyExperimentsUnion =
    Types extends infer U ?
        U extends Types ?
            MyExperiment<U>
        : never
    : never;
// MyExperiment<"text"> | MyExperiment<"date"> | MyExperiment<"articles"> | MyExperiment<"params">

Alternatively, your example could also be achieved like this

type MyExperimentsUnion<T extends Types = Types> = T extends any ? MyExperiment<T> : never;
// Using MyExperimentsUnion without a type parameter will result in
// MyExperiment<"text"> | MyExperiment<"date"> | MyExperiment<"articles"> | MyExperiment<"params">

* This is purely speculative on my part, as I haven't delved deeply into how TypeScript evaluates these scenarios.

Answer №3

Perhaps only valued at two cents, yet here are my thoughts:

type Types = 'text' | 'date' | 'articles' | 'params';
type MyExperiment<Type extends Types> =  { t : Type };

type MyExperimentsGenericUnion<T extends Types> = T extends (infer U) ? MyExperiment<U> : never;
// encountering the same issue

type MyExperimentsUnionConstraint = any extends MyExperiment<infer U> ? MyExperiment<U> : never;
// no errors detected

I can see why MyExperimentsUnionConstraint functions while MyExperimentsUnion does not, though articulating it may require a deeper understanding of the language.

To illustrate by example:

  • In the case of MyExperimentsUnion, inferring U as Types | 'bla' from Types extends U results in MyExperiment<Type | 'bla'> which is problematic.
  • With MyExperimentsUnionConstraint, U is limited to values compatible with MyExperiment.

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

Testing React-Redux Containers with JestIs this okay or would

Embarking on my journey in React with Redux, I am currently working on creating a TestUnit for a container that links to a dialog responsible for rendering a table. Within the container, I have: a mapStateToProps constant which provides properties for t ...

What is the recommended approach for returning two different types in a TypeScript function?

My API function currently performs a post request and returns an Observable of ModelAResponse, which is an interface I have defined. I now want to modify this function so that it can return an Observable of either ModelAResponse or ModelBResponse based on ...

Experiencing TypeScript error in VSCode while trying to run in Nodejs? Here's how to troubleshoot and resolve

Experimenting with the performance measurement code provided by Nodejs in VSCode has been an interesting challenge for me. I encountered no issues running the code in Nodejs, and it executed smoothly. However, when attempting to run the code in VSCode, er ...

Troubleshooting: Ionic Cordova's Post Functionality Fails to

I am a newcomer to Hybrid application development, currently utilizing Ionic Cordova for my project. My aim is to implement a POST method within the application. var url = "http://XXXXXXXXXXXXX.com/XXXX"; var headers = new Headers(); headers.append("Acce ...

Encountered an error while trying to access a property that is undefined - attempting to call

In my TypeScript class, I have a method that retrieves a list of organizations and their roles. The method looks like this: getOrgList(oo: fhir.Organization) { var olist: orgRoles[] = []; var filtered = oo.extension.filter(this.getRoleExt); f ...

Utilizing Angular and Typescript for Enhanced Modal Functionality: Implementing Bootstrap Modals in Various Components

When working in Angular, I have a component called Modal. I need to open the same Modal Component from two different places. The catch is, I want the button text in the Banner image to say "Get Started Now". Check out the Image linked below for reference. ...

Utilizing both Typescript and javascript in a unified project

Recently, I've been working on a NodeJS project and wanted to incorporate TypeScript files. In my initial attempt, I created a TypeScript file with the following content: utilts.ts : export const delimitify = ( strings:Array<string>, delimiter: ...

There were no visible outputs displayed within the table's tbody section

import React from 'react'; export default class HelloWorld extends React.Component { public render(): JSX.Element { let elements = [{"id":1,"isActive":true,"object":"Communication","previ ...

Menu item currently unavailable

I am looking to disable the selected item menu when it is clicked until there is no response. I am curious if there is a universal way to achieve this. For example: <ng-template [ngIf]="item.hasSidebar"> <li [hidden]="itemHidden(item.keyPa ...

Using private members to create getter and setter in TypeScript

Recently, I developed a unique auto getter and setter in JavaScript which you can view here. However, I am currently unsure of how to implement this functionality in TypeScript. I am interested in creating an Object Oriented version of this feature if it ...

Using TypeScript with Watermelondb

I'm currently developing a React App and I want to implement Watermelondb for Offline Storage, but I'm unsure about using it with TypeScript. I have already set up the database and created Course and Lesson model files from the Watermelondb libra ...

Encountering difficulty in reaching the /login endpoint with TypeScript in Express framework

I'm currently working on a demo project using TypeScript and Express, but I've hit a roadblock that I can't seem to figure out. For this project, I've been following a tutorial series from this blog. However, after completing two parts ...

Converting a dynamic JSON object into a generic type in TypeScript

I need assistance with converting a JSON object into the equivalent generic type in TypeScript. The JSON object I have contains dynamic keys such as applications and permissions. The keys inside applications, like application_management and user_managemen ...

Utilizing AMD Modules and TypeScript to Load Bootstrap

I am attempting to incorporate Bootstrap into my project using RequireJS alongside typescript AMD modules. Currently, my requireJS configuration looks like this: require.config({ shim: { bootstrap: { deps: ["jquery"] } }, paths: { ...

What is the best way to incorporate tailored validation into reactive forms in Angular?

I'm facing an issue with my form where I'm trying to display a specific error message based on certain conditions. Currently, my form is functioning but it's throwing a type error stating "undefined is not an object". I'm struggling to ...

Achieving a similar functionality to Spring Security ACL in a Node.js AWS Lambda serverless environment

I am tackling a javascript challenge that has me stumped. Specifically, I am trying to figure out how to implement fine-grained authorization using an AWS serverless approach. In Spring security ACL, users can be banned from specific tasks at the instanc ...

Tips for dynamically incorporating filtered selections into a Mat-Select dropdown

I am seeking guidance on how to prevent changing the values of already selected values in other rows when each row of the formArray is altered. Adding controls dynamically and correctly retrieving values in filters are functioning properly. The issue arise ...

What is the purpose of having a tsconfig.json file in every subdirectory, even if it just extends the main configuration file?

My goal is to streamline the configuration files in my front-end mono repo by utilizing Vite with React and TypeScript. At the root of my repository, I have set up a tsconfig.json file that contains all the necessary settings to run each project, including ...

Creating an interface that accurately infers the correct type based on the context

I have an example below of what I aim to achieve. My goal is to start with an empty list of DbTransactInput and then add objects to the array. I experimented with mapped types to ensure that the "Items" in the "Put" property infer the correct data type, w ...

I am currently struggling with adding an HTML form to my Angular project

Currently utilizing Angular framework My Add button triggers the appending of HTML content upon multiple clicks. The issue arises when I click the Add button, as the appended content fails to display textboxes or dropdowns. Instead, only the field names ...