Using TypeScript to define multiple extended conditions in a single line

Currently in the process of converting my javascript project to typescript, and I must say, the learning stage has been quite enlightening. Converting the project has taught me a lot so far. While I did encounter a challenge in my code which I managed to resolve, the issue now is that I have multiple conditions for it, and extending 4 or 5 times for the same result seems impractical.

Below is the code snippet:

type GetModel<M> = IsUnion<M> extends true
  ? UserModel
  : M extends typeof types.FRONT
  ? UserModel
  : AdminModel;

Playground: Playground Link

I am aiming to simplify the above code into something more linear, like the example below, but for some reason, it's not functioning as expected:

type GetModel<M> = IsUnion<M> extends true | M extends typeof types.FRONT
  ? UserModel
  : AdminModel;

My goal is to achieve the same result as demonstrated in the playground link above.

type user = GetModel<1 | 2>; // user
type user1 = GetModel<2>; // user
type admin = GetModel<1>; // admin

Answer №1

Let's kick things off with the simple logical operator OR, which takes two conditions and evaluates to true if either of them is true, otherwise it returns false.

In order to implement this, we need some utility types from the type-samurai package:

Extends - Checks if the first argument extends the second argument

type Extends<T, Base> = T extends Base ? true : false;

If - Returns the second argument if the first argument is true, otherwise returns the third argument

type If<
  Condition,
  IfTrue = true,
  IfFalse = false
> = Condition extends true ? IfTrue : IfFalse;

IfExtends - Returns the fourth argument if the first argument extends the second argument, else returns the fifth argument

type IfExtends<T, Base, IfTrue = true, IfFalse = false> = If<
  Extends<T, Base>,
  IfTrue,
  IfFalse
>;

IsEmptyArray - Checks if an array is empty or not

type IsEmptyArray<T extends readonly unknown[]> = T extends readonly [
  unknown,
  ...unknown[]
]
  ? false
  : true;

For the logical OR operation, we can leverage the use of If type to determine the outcome based on the conditions provided:

type Or<Condition1, Condition2> = IfExtends<
    Condition1,
    true,
    true,
    IfExtends<Condition2, true>

Testing the implementation:

// true
type Case1 = Or<true, true>
// true
type Case2 = Or<true, false>
// true
type Case3 = Or<false, true>
// false
type Case4 = Or<false, false>

Additionally, for handling more than two conditions, a new type OrArr is introduced to handle arrays of conditions with recursive operations.

  • Return true if the array is empty
  • ... (content continues in similar fashion, as per original text)

Implementation of OrArr:

(implementation code here)
... (remaining content follows similarly as in the original text)

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

In TypeScript, vertical bars and null are commonly used for type unions

Greetings! I am just starting to learn JavaScript and TypeScript I have a question about the code snippet below What does the pipe symbol (|) signify? Also, why is null = null being used here? let element: HTMLElement | null = null; ...

Issue encountered with the inability to successfully subscribe to the LoggedIn Observable

After successfully logging in using a service in Angular, I am encountering an error while trying to hide the signin and signup links. The error message can be seen in this screenshot: https://i.stack.imgur.com/WcRYm.png Below is my service code snippet: ...

How can I access the results returned by Firebase functions?

My attempt to retrieve json data from a firebase function request is not working as expected. Here's the code I have tried: export const listener = functions.https.onRequest(async (req, res) => { return {foo:"bar"} }) When I access the approp ...

Creating TypeScript definition file bundle using webpack

Currently, my method involves using "gulp" to generate the definition file for my bundle in the following way: dtsGenerator.default({ name: 'ngFramework', project: './', out: './Typings/raw/index.d.ts' }); Howeve ...

The term "define" is not recognized when constructing a Next.js application

Currently, I am working with Next version 10.0.1 and React 17.0.2. While attempting to build my Next app, I encountered the following error: ReferenceError: define is not defined at Object.<anonymous> (/Users/username/Desktop/project/node_module ...

a guide on accessing key value elements within an array using Ionic 3

Just diving into the world of Ionic, I am currently working on a task to showcase products on the cart page that have been added to the cart. Upon fetching data from a REST API, I can see the response below in the console. "items": { "29.2.2.0.YTowOnt ...

The main module's postinstall process is initiated before the sub-module's postinstall process

Update: I am seeking guidance on how to install a module from GitHub instead of npm. That's the main query. In case you're wondering why: I'm currently working on some confidential projects and prefer not to publish the code. As a result, ...

What is the reason for TypeScript disabling unsecure/non-strict compiler rules by default?

Recently, I found myself having to enable a slew of compiler options in my application: "alwaysStrict": true, "extendedDiagnostics": true, "noFallthroughCasesInSwitch": true, "noImplicitAny", true, "noImplicitThis", true, "noImplicitReturns": true, "noUnu ...

Is it possible to integrate TypeScript 5.0 decorators into React components?

Every time I add decorators to my class, they always get called with the arguments specified for legacy decorators: a target, property key, and property descriptor. I am interested in using TypeScript 5.0 decorators. Is this feasible, and if so, how can I ...

Discover the latest DOM elements using Webdriverio 5

Currently, I am developing a REact based CMS application that features a form with multiple carousels. I am encountering an issue where the webdriverio implementation is unable to locate an element, even though the same xpath works fine when tested manua ...

Convert an object to an array, but only if it is not already an array

If we need to iterate over either an Object or an Array of Objects, we can transform the Object into an array of one object and then iterate in our React App accordingly. Let's consider an example: // Returned value as object const zoo = { lion: &a ...

Organizing Firebase functions: Managing multiple functions and dependencies

Objective I aim to gain a deeper understanding of how the firebase CLI manages the deployment process for multiple firebase functions, each stored in different files, and how it handles dependencies that are specific to certain functions. Situation If I ...

Using Omit<T,K> with enums does not yield the expected result in Typescript

The setup includes an enum and interface as shown below: enum MyEnum { ALL, OTHER } interface Props { sources: Omit<MyEnum, MyEnum.ALL> } const test: Props = { sources: MyEnum.ALL } // triggering a complaint intentionally I am perplexed b ...

Error encountered while testing karma: subscription function is not recognized

I encountered an issue with my karma unit test failing with the following error message. "this.gridApi.getScaleWidth().subscribe is not a function" GridApi.ts export class GridApi { private scaleWidthSubject = new BehaviorSubject<{value: number}& ...

What causes TypeScript to automatically infer a default property when dynamically importing a JavaScript file that lacks a default export?

While dynamically importing a javascript file that exports multiple functions (without a default export), I encountered this issue: const sayHi = import('./sayHi.js') I was expecting the type of sayHi to be Promise<{name1: function, name2: fu ...

Excluding the decimal point from version 1.0 in an API response with Angular 5

When working with Angular 5, I encountered an issue where the API response was returned as 1.0, but when displayed in the HTML field it only showed as 1. Upon inspecting the response in Chrome dev-tools, under the Network tab -> Response, it correctly ...

Resolving NgModule Import Errors During Migration of Angular Project from Version 11 to 16

Currently, I am in the process of upgrading an existing Angular project from version 11 to version 16. The update went smoothly until I encountered a roadblock upon reaching version 16. The main issue I am facing is that most of my modules are displaying ...

Incorrect type declarations in Typescript navigation.push in React Native cause unexpected behavior

Currently in my react native application, I have integrated @react-navigation/native-stack. However, the following line of code is causing an error: navigation.push('ScreenName', {myParam}); The error message reads as follows: TS2345: Argument ...

How can I establish default values for 2 to 3 options in a Dropdownlist?

Is there a way to set two values as default in a dropdown list, and when the page is refreshed, the last two selected values are retained as defaults? Thanks in advance! Visit this link for more information ...

What is the best way to store the output of a function in a local variable?

In my Type Script code, I am looking to store the return value of a function in a local variable. The process is outlined below: getdetail1(store){ let Cust_id=this.sharedata.latus_lead.m_type let url="http:domain.com" console.lo ...