Expand the font manually

Is there a way to define a type that represents the widened version of another type?

Consider the following scenario:

function times<A extends number, B extends number>(a: A, b: B): A & B;

The intention behind this times function is to preserve any extensions on types A and B, while the value itself becomes a * b.

The issue arises when calling times(2, 3) gives a return type of 2 & 3, which is both inaccurate and unattainable. Instead of 6, I neither want nor need it to be 2 & 3; my desired output in this case should be number.

Type widening typically happens automatically in Typescript through intricate rules. While it often causes confusion, in this particular instance, it's what I'm looking for but not getting. I seek a method to specify a return type of

WidenedVersionOf<A> & WidenedVersionOf<B>
. Is there a solution available for this requirement?


Addressing the anticipated question of "why not use composition?"

In this context, the extensions to number types hold significance. Although using a wrapper object with the value stored as a number and the extension separately kept would usually be the preferred approach, this situation differs. Our utilization involves branded primitives for units of measure (e.g., seconds, feet). These extensions exist exclusively in the type domain and do not manifest at runtime, offering several advantages.

We operate with a limited range of brandings (primarily In, Per, and

Delta</code), enabling constructions like <code>const v = 20 as number & In<'feet'> & Per<'second'>
or
const d = 100 as number & In<'feet'> & Delta
). To accommodate all scenarios, the times function incorporates numerous overloads. However, generic containers that store numbers of varying branding types using N extends number encounter challenges with the overload of times as described earlier. It is impractical (and likely impossible) to have each generic container handle every possible combination of In, Per, and/or Delta cases individually.

Answer №1

My interpretation of the issue is that when using In<T> as per your question, the intersection In<A> & In<B> does not truly represent In<A*B>. Therefore, a different approach is needed to generate the type corresponding to A*B which accounts for units, cancellation, etc. Intersection alone cannot achieve this. Here's my take on it:

class In<T> { private __v!: T };

function withUnit<N extends number, T extends string>(n: N, t: T): N & In<T> {
  return n as any;
}
const oneNewton = withUnit(1, "Newtons"); // 1 & In<"Newtons">
const oneMeter = withUnit(1, "meter"); // 1 & In<meter>

Does this align with your approach so far?

The use case for Widen is specific - it only applies to types in the form of number & In<T>. Currently, there is no mechanism to extract individual types from intersections programmatically. For example, given a type 5 & Foo & Bar & Baz, isolating Bar automatically isn't feasible without prior knowledge of its existence.

type Widen<N extends number> = N extends In<infer T> ? number & In<T> : number;

Below is the implementation of times as requested:

declare function times<A extends number, B extends number>(a: A, b: B): Widen<A> & Widen<B>;

Here are some examples showcasing how it operates:

const six = times(2, 3); // number
const twoMeters = times(2, oneMeter); // number & In<"meter">
const alsoTwoMeters = times(oneMeter, 2); // number & In<"meter">;

However, in certain scenarios, unexpected outcomes may occur due to aforementioned limitations:

const oneSquareMeterUhWait = times(oneMeter, oneMeter); // number & In<"meter">;    
const twoNewtonMetersUhWait = times(2, times(oneNewton, oneMeter)); 
// number & In<"Newtons" & "meter">

The core concept behind Widen enables extraction and combination of unit types within numeric types. But fusion at the type level, exceeding the present scope, necessitates further exploration.

Hope this explanation sheds some light! Best of luck!

Link to code

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

Why is it that in reactive forms of Angular, the parameter being passed in formControlName is passed as a string?

I am currently working on a reactive form in Angular. In order to synchronize the FormControl object from the TypeScript file with the form control in the HTML file, you need to utilize the formControlName directive. This is accomplished as shown below: f ...

The attribute 'NameNews' is not recognized in the specified type when running ng build --prod

Definition export interface INewsModule{ IDNews:number; IDCategoery:number; NameNews:string; TopicNews:string; DateNews?:Date; ImageCaption:string; ImageName:string ; } Implementation import { Component, OnInit, Input, I ...

Active Angular component utilizing *ngIf during the programmatically lazy loading of a Module

I find myself in a situation where I need to load numerous components on a specific route within my application. These components are controlled by a logic with *ngIf directives that allow me to show or hide them dynamically. For instance: <div *ngIf=& ...

Inspect the TypeScript typings within Svelte documents directly from the terminal

When I run tsc --noemit, it successfully checks for type errors in the codebase. However, I have encountered an issue where it does not seem to check .svelte files. Is there a way to enable this functionality? I can see the type errors in .svelte files wh ...

Managing conflicting versions of React in a component library created with Webpack and Storybook

My goal is to create a React component library on top of MUI using Storybook and TypeScript. Since Storybook is based on Webpack (which includes SASS files), I'm utilizing Webpack to build the bundle because TSC can't compile those files. Subsequ ...

Guide to automatically blur the input field and toggle it upon clicking the checkbox using Angular

<input (click)="check()" class="checkbox" type="checkbox"> <input [(ngModel)]="second_month" value="2019-09" type="month" [class.blurred]="isBlurred">> I need the second input(type=month) field to be initially blurred, and only unblur ...

Getting an error in Typescript: 'Operator '!==' cannot be used with types' while working with enums

When comparing enums, I encountered a perplexing error message stating "Operator '!==' cannot be applied to types," whereas the same comparison with integer values did not result in an error: enum E { A, B, C, D, E, F } ...

acquiring environmental variables in TypeScript for node applications

I am struggling with accessing process.env variables in my TypeScript pages. It seems to be a scope issue, which doesn't make sense to me as a beginner in TypeScript. To get my environment variables, I use a YAML file and attach them to the running p ...

Send the Children prop to the React Memo component

Currently, I am in the stage of enhancing a set of React SFC components by utilizing React.memo. The majority of these components have children and the project incorporates TypeScript. I had a notion that memo components do not support children when I en ...

Trigger functions on a universal component from the nested component

I am currently working on an Angular project with two components, one being a generic component where the table is defined and the other being a component that invokes this table by passing the required data. However, I encountered an issue where the tabl ...

Angular Material's compatibility update for Angular 8 version

Currently, I'm in the midst of a project that relies on Angular v 8.2.14, and I'm interested in incorporating Angular Material controls into it. I've made an effort to integrate Angular Material into my project, however, the default version ...

Combining default and named exports in Rollup configuration

Currently, I am in the process of developing a Bluetooth library for Node.js which will be utilizing TypeScript and Rollup. My goal is to allow users to import components from my library in various ways. import Sblendid from "@sblendid/sblendid"; import S ...

Is it advisable for a component to handle the states of its sub-components within the ngrx/store framework?

I am currently grappling with the best strategy for managing state in my application. Specifically, whether it makes sense for the parent component to handle the state for two subcomponents. For instance: <div> <subcomponent-one> *ngIf=&qu ...

Exploring the depths of Rx.ReplaySubject: Techniques for delaying the `next()` event

Confused Mind: Either I'm mistaken, or the whiskey is starting to take effect. (I can't rule out the possibility that I'm just going crazy. Apologies for that.) Assumption: My assumption was that ReplaySubject would emit a single value eve ...

To determine if two constant objects share identical structures in TypeScript, you can compare their properties

There are two theme objects available: const lightMode = { background: "white", text: { primary: "dark", secondary: "darkgrey" }, } as const const darkMode = { background: "black", text: { prim ...

What is the best way to invoke a function in a specific child component from its parent component?

It seems that I might have provided too much information, but the main question remains: how can I call a method in the child component from the parent template's click() event. <button(click)='get()'>GET</button> In my case, th ...

Get the dynamic type as the return value in a TypeScript abstract class method with generic type T

Within my codebase, I have created an abstract class: export abstract class Filters<P> { protected field: string; protected constructor(field: string) { this.field = field; } protected abstract getFilter(): P; } Additionally, there is ...

Displaying Typescript command line options during the build process in Visual Studio

As I delve into the world of VS 2015 Typescript projects, I find myself faced with a myriad of build options. Many times, the questions and answers on Stack Overflow mention command line options that I'm not completely familiar with, especially when i ...

How can I update a property within an object in a sequential manner, similar to taking turns in a game, using React.js?

I am currently working on a ReactJs project where I am creating a game, but I have encountered an issue. I need to alternate turns between players and generate a random number between 1 and 10 for each player, storing this random number inside their respec ...

The declaration file for the module 'vue-html-to-paper' was not located

Struggling to make a sample project work with HTML to PDF, but encountering an error message stating: Could not find a declaration file for module 'vue-html-to-paper' Even though it resides in my node_modules index.js import Vue from 'vue& ...