The TypeScript algorithm for inferring types in conditional statements

I am interested in understanding how Typescript infers types in signatures using conditional types.

Example 1: demonstrates correct inference of T as number:

type Args<T> = { value: T }

function foo<T>(args: Args<T>) { return args; }

// correctly inferred as foo<number>
foo({ value: 123 });

Example 2: explores conditional types and the inference of unknown:

type StringOrNever<T> = T extends string ? string : never;
type Args<T> = { value: StringOrNever<T>; }

function foo<T>(args: Args<T>) { return args; }

// both calls inferred as foo<unknown> :(
foo({ value: 123 });
foo({ value: "some string" });

Example 3: discusses expected inference but with unusual types:

type StringOrNever<T> = T extends string ? string : never;
type Args<T> = { value: StringOrNever<T> & T; }

function foo<T>(args: Args<T>) { return args; }

// inferred as foo<number>
foo({ value: 123 });

// inferred as foo<"Typescript">
foo({ value: "Typescript" });

My questions are:

  1. Why does Typescript infer unknown for T in example 2, and what causes it to infer types as expected in example 3?
  2. Is there a general algorithm that Typescript follows to infer generic type arguments, such as trying a sequence of candidates where the first candidate is always the argument type and the last resort is unknown?

Answer №1

Understanding generic type inference in TypeScript can be challenging at times. The concept involves substituting a generic type with a specific type based on the given argument.

For instance, consider the first example:

function foo<T>(args: { value: T }) { return args; }

If you provide a value of type { value: string }, the generic type T can be replaced with string.

However, the same does not apply to example 2:

type StringOrNever<T> = T extends string ? string : never;

function foo<T>(args: { value: StringOrNever<T> }) { return args; }

In this case, T is only used for comparison and cannot be substituted by the actual type. Therefore, the default type unknown is inferred.

To ensure successful inference, T should be placed on the right side of the conditional, as shown below:

type StringOrNever<T> = T extends string ? T : never;

function foo<T>(args: { value: StringOrNever<T> }) { return args; }

This approach allows TypeScript to infer the type T based on the provided type of value.

Try it out in the 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

struggling to locate name using typescript and deno

Here is the snippet of code I'm working with: /** * map.ts */ // @deno-types="./libs/@types/geojson/index.d.ts" // @deno-types="./libs/@types/mapbox-gl/index.d.ts" mapboxgl.accessToken = "toto"; var map = new mapbo ...

What causes the discrepancy in values displayed by enums in TypeScript when assigned integers in reverse order?

Recently diving into the world of TypeScript, I've been experimenting with different types in this language. One interesting data type I played with is enums. Here's an example of code I used: enum colors {red=1,green=0,blue,white}; console.lo ...

I am in the process of transitioning my JSX website to TSX and am struggling to figure out the proper placement of my type definitions

As the title suggests, I am in the process of migrating an application that I developed using the Google Maps API for rendering maps. In this app, I display information on maps and include functionality to zoom in when a user clicks on something. The erro ...

I don't understand what's happening with this ternary format in the Typescript function - something seems off

Exploring Typescript. While browsing through a project's codebase, I stumbled upon the following snippet and am unsure of its validity. Can anyone shed light on what this code is doing? It seems to be dealing with default values, but I'm not enti ...

Watching videos is quite a time-consuming process due to the long loading times

I recently created a website at , and I am facing an issue with the homepage video taking too long to play. While it works fine on a PC, it seems to load very slowly on mobile browsers. Any suggestions on how I can improve its loading speed? <video cl ...

I am unable to add a new property to the request object in the Express framework

My goal is to add a new property to the request object in typescript. Here's the code snippet I'm using: import { request, Request, response, Response } from "express"; ((req: Request, res: Response) => { console.log(req.user); ...

What are the steps to execute jest in an AWS Lambda environment?

I'm looking to execute my end-to-end test post-deployment for the ability to revert in case of any issues. I've followed the guidelines outlined in this particular blog post. Below is my lambda function: export async function testLambda(event: A ...

Can you pass a generic type as a parameter for another generic in Java?

Simply provide a generic type like a callback: type FUNC<ARG,RET, F> = (arg: ARG) => F<RET>; type PROMISE<T> = Promise<T>; type IDENT<T> = T; type A = FUNC<number, void, IDENT>; type A_PROMISE = FUNC<number, void, ...

Issue with React not displaying JSX when onClick Button is triggered

I've recently started learning React and I'm facing a problem that I can't seem to figure out. I have a basic button, and when it's clicked, I want to add another text or HTML element. While the console log statement is working fine, th ...

The parameter of type 'never' cannot be assigned with the argument of type 'number | boolean | undefined'

In my project, I am creating a validation input using TypeScript in Next.js. interface InputRules { required?: boolean min?: number max?: number minLength?: number maxLength?: number } I have defined an object that contains methods to handle val ...

Declarations of Typescript React for Props for Specific Element

I am trying to specify types for certain elements like <button> or <input>, but I am unable to differentiate between specific element types. Here is an example: interface Props{ component: React.ComponentProps<"button"> | nev ...

Synchronize Docker volumes

Hey there! I've been trying to dive into learning Docker, but I'm having trouble syncing the host and container using volumes when making changes and saving code (specifically using npm run dev). Every time I need to restart docker-compose up --b ...

Angular 14 Observables are not triggering resize events

There seems to be an issue here, as the code is not being triggered at all. The console log is not printing and this.width is not changing. constructor(private host: ElementRef, private zone: NgZone) {} public ngOnInit(): void { this.observer = new Re ...

Building a route to a link in Next.js: A step-by-step guide

Having trouble setting up routes to my Next.js portfolio project page. I've created an array of pages and their links in the index.ts file within the data folder, but I'm facing issues with routing. I've integrated a floating navigation usi ...

The module 'angular' could not be located and is causing an error

Currently, I am in the process of transitioning from Angular 1 to Angular 2 following this guide: . However, when I try to run the application using npm start, it displays an error saying 'Cannot find module 'angular''. This is a snipp ...

Typescript: When using ts-node-dev, an error occurred while trying to import express due to an unexpected

I am embarking on a fresh project using Typescript and I intend to set up the node server with typescript utilizing express. There's a helpful tutorial that explains how to execute a Typescript file without going through the hassle of compiling files, ...

The Array instance does not reflect changes made by the HTTP service request

Currently, I am tackling a situation where I must retrieve a series of objects from Spring Boot by making REST calls and then display them in the user interface using Angular 5. This is what my component looks like: export class BusinessComponent impleme ...

Triggering event within the componentDidUpdate lifecycle method

Here is the code snippet that I am working with: handleValidate = (value: string, e: React.ChangeEvent<HTMLTextAreaElement>) => { const { onValueChange } = this.props; const errorMessage = this.validateJsonSchema(value); if (errorMessage == null ...

Attempting to create a function that removes the first and last characters from a string, however encountering issues with the code in TypeScript

Currently, I am delving into the world of TypeScript and facing a challenge. The task at hand involves creating a function that returns a string without its first and last character. Can anyone offer assistance with this problem? Below is the code along wi ...

Tips for navigating to a different route during the ngOnInit lifecycle event

How can I automatically redirect users to a specific page when they paste a URL directly into the browser? I would like users to be directed to the /en/sell page when they enter this URL: http://localhost:3000/en/sell/confirmation Below is the code I am ...