Typescript is struggling to accurately deduce types from interim definitions of types

I have defined the following types.

type Triple<A, B, C> = A & B & C;
type First<T> = T extends Triple<infer A, infer _B, infer _C> ? A : never;
type Second<T> = T extends Triple<infer _A, infer B, infer _C> ? B : never;
type Third<T> = T extends Triple<infer _A, infer _B, infer C> ? C : never;

// Scenario1: Expected behavior

type F1 = First<Triple<{ x: number }, { y: string }, { z: boolean }>>; // { x: number }
type S1 = Second<Triple<{ x: number }, { y: string }, { z: boolean }>>; // { y: string }
type T1 = Third<Triple<{ x: number }, { y: string }, { z: boolean }>>; // { z: boolean }


// Scenario2: Unexpected behavior

type XYZ = Triple<{ x: number }, { y: string }, { z: boolean }>;

type F2 = First<XYZ>; // unknown
type S2 = Second<XYZ>; // unknown
type T2 = Third<XYZ>; // unknown

Could someone clarify why the resulting types in Scenario2 are showing as unknown? View it in action on typescript playground.

Answer №1

Types in typescript are structured based on set theory, allowing the properties that apply to sets to also apply to them.

This is why operators like & and | exhibit Commutative properties, meaning their orders can be switched.

A & B == B & A

A | B == B | A

Essentially, this flexibility enables the typescript compiler to rearrange the order and placement of the operands(types).

The infer keyword functions when a specific structure and positions are defined, allowing the compiler to provide values for those positions.

type Triple<A, B, C> = A & B & C;
type First<T> = T extends Triple<infer A, infer _B, infer _C> ? A : never;
type Second<T> = T extends Triple<infer _A, infer B, infer _C> ? B : never;
type Third<T> = T extends Triple<infer _A, infer _B, infer C> ? C : never;

Scenario 1 :

Type inferences are made from the type parameter of Triple during instantiation, allowing typescript to determine their designated positions for inference.

type F1 = First<Triple<{ x: number }, { y: string }, { z: boolean }>>; // { x: number }
type S1 = Second<Triple<{ x: number }, { y: string }, { z: boolean }>>; // { y: string }
type T1 = Third<Triple<{ x: number }, { y: string }, { z: boolean }>>; // { z: boolean }

Scenario 2 :

Type values are instantiated first, making it uncertain whether the type will remain as A & B & C.

Typescript could potentially store and manipulate it as B & A & C or C & A & B, among other variations.

Due to this uncertainty, the resulting type is marked as unknown.

type XYZ = Triple<{ x: number }, { y: string }, { z: boolean }>;

type F2 = First<XYZ>; // unknown
type S2 = Second<XYZ>; // unknown
type T2 = Third<XYZ>; // unknown

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

How to toggle CSS class in Angular2/Typescript to mimic radio buttons behavior

Is there a way to create a radio button group using UL and LI elements in Angular2 and Typescript? The goal is to have all the anchors function like a radio button group where only one can be selected at a time. The selected anchor should remain "clicked" ...

NextAuth credentials are undefined and authentication is malfunctioning in React

I encountered the following issue: https://i.sstatic.net/3VBoJ.png This is the code snippet that I am using: return ( <> {Object.values(providers).map((provider) => { if (provider.id === "credentials") { ret ...

Tips for integrating Tinymce in Angular 2 once it has reached its stable version

How to Implement TinyMCE in Angular 2 with Two-Way Binding Working with Third-Party Libraries in Angular 2 After trying multiple solutions provided on stackoverflow, I am still unable to load the TinyMCE editor successfully. I am wondering if there are ...

Comparing two arrays in Angular through filtering

I have two arrays and I am trying to display only the data that matches with the first array. For example: The first array looks like this: ["1", "2" , "3"] The second array is as follows: [{"name": "xyz", "id": "1"},{"name":"abc", "id": "3"}, ,{"name ...

VS Code is throwing an Error TS7013, while Typescript remains unfazed

In my Typescript/Angular project, I have the following interface: export interface MyInterface { new (helper: MyInterfaceHelpers); } After compiling the project, no errors are shown by the Typescript compiler. However, VSCode highlights it with squiggl ...

What is the best way to update the state of a response from an API call for a detailed object using React context, so that there is no need to retrigger the API call

I'm currently developing a react native typescript project. How can I assign the data received from an API call to my context object? I want to avoid making the API call every time the component is loaded. Instead, I want to check if the context alr ...

In order for the expansion parameter to be successfully used, it must be either of tuple type or passed to the

const myFunction = function(arg1: number, arg2: number, arg3: number) {} const myFunction1 = function() {} const obj = { myFunction, myFunction1 }; type FuncType = typeof obj; function executeFunction<T extends keyof FuncType>(key: ...

What is preventing typescript from inferring these linked types automatically?

Consider the following code snippet: const foo = (flag: boolean) => { if (flag) { return { success: true, data: { name: "John", age: 40 } } } return { success: false, data: null } ...

Define a new type in Typescript that is equal to another type, but with the added flexibility of having optional

I have 2 categories: category Main = { x: boolean; y: number; z: string } category MainOptions = { x?: boolean; y?: number; z?: string; } In this scenario, MainOptions is designed to include some, none, or all of the attributes that belong to ...

Issue encountered when attempting to access disk JSON data: 404 error code detected

I am attempting to retrieve JSON data from the disk using a service: import { Product } from './../models/Product'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { HttpClient } from &apo ...

Issue with Angular 8: discrepancy between the value utilized in component.html and the value stored in component.ts (Azure application service)

Encountering a peculiar behavior in one of my Angular applications. In the component.html file, I aim to display "UAT" and style the Angular mat elements with a vibrant orange color when in UAT mode, while displaying them in blue without any mention of UAT ...

A Typescript object that matches types and eventually returns a string when called upon

In the process of overengineering a type that can match either a string or an object whose valueOf() function, when evaluated recursively, ultimately returns a string. type Stringable = string | StringableObject; interface StringableObject { valueOf() ...

What is the best way to define multiple variables in ionic 2 using Angular2 and TypeScript?

I'm brand new to working with ionic2/Angular2/Typescript. My project involves creating a wheel with eight slices, but I'm struggling with how to declare multiple variables. In JavaScript, I've declared them like this: function rand(min, max ...

Jest assertions encountering type errors due to Cypress

After using react-testing-library and @testing-library/jest-dom/extend-expect, I decided to install Cypress. However, I now face Typescript errors on all my jest matchers: Property 'toEqual' doesn't exist on type 'Assertion'. Did ...

Is it possible to link fields with varying titles in NestJS?

Currently, I am developing a NestJS application that interacts with SAP (among other external applications). Unfortunately, SAP has very specific field name requirements. In some instances, I need to send over 70 fields with names that adhere to SAP's ...

"iOS users have reported that notifications from Firebase have mysteriously ceased to

Yesterday evening, I was experimenting with Push Notifications from Firebase on my iOS application and everything was functioning correctly. I successfully sent a notification from a Cloud Function to a specific FCM token. However, this morning, notificat ...

What is the best way to obtain an attribute name that is reminiscent of Function.name?

My objective is to securely type an attribute. For example, I have an object: const identity = { address: "Jackie" }; At some point, I will rename the address key to something else, like street_address. This is how it is currently implemented ...

"The list of table rows in a React application using Typescript is not rendering properly

I am encountering an issue where the rows in my table are not being rendered while trying to map objects from a list called items. I am working with typescript and react-bootstrap. Can someone help me understand why this is happening and how to resolve it? ...

Generic Abstract Classes in TypeScript

In my TypeScript code, I have an abstract generic class with a method that takes a parameter of a class type variable. When I tried to implement the abstract method in a derived class, I noticed that the TypeScript compiler doesn't check the type of t ...

Blend the power of Node's CommonJS with the versatility of Typescript's ES modules

I currently have a Node.js v10 legacy application that was built using CommonJS modules (require). The entire codebase is written in JavaScript. However, I am considering upgrading the app and refactoring a specific part of it to use TypeScript modules ( ...