Output is guaranteed to be non-null and is determined by the type of input received

Is there a way to consolidate the functions getStringOrFail and getNumberOrFail into a single function that handles different argument types?

export const getOrFail = <T>(value: T | null, message: string): T => {
  if (value !== null) return value;
  throw new Error(message);
}

I attempted using generics but encountered the issue of being able to return null. How can I refactor this code to achieve my goal?

Answer №1

Consider using a general approach, with the caveat that T must be a type that extends {}.

export function getOrFail<T extends {}>(value: T | null | undefined, message: string = "getNumberOrFail error"): T {
  if (value != null) return value;
  throw new Error(message);
}

{} indicates inclusion of all types except for null or undefined.

Further details can be found here.

Answer №2

To accomplish this, you need to define a generic parameter that excludes the possibility of being null:

export const getOrFail = <T extends string | number>(value: T | null, message: string = 'getOrFail error'): T => {
  if (value !== null) return value
  throw new Error(message);
}

Playground

In line with @jcalz's suggestion, for a more versatile approach that allows everything but null, you can use {} | undefined | void instead of string | number:

export const getOrFail = <T extends {} | undefined | void>(value: T | null, message: string = 'getOrFail error'): T => {
  if (value !== null) return value
  throw new Error(message);
}

Answer №3

Just wanted to share another method for the sake of completeness (not saying it's better than the rest), utilizing a conditional return type that utilizes Exclude to filter out null:

export const getOrFail = <T>(
  value: T | null,
  message: string = "getOrFail error"
) => {
  if (value !== null) return value as Exclude<T, null>;
  throw new Error(message);
};

You can test its behavior with these examples:

const bool = getOrFail(true); // boolean
const nevr = getOrFail(null); // never
const undef = getOrFail(undefined); // undefined
const strng = getOrFail(Math.random() < 0.5 ? "hello" : null); // string

The last example takes a parameter of type string | null and returns a type of

Exclude<string | null, null>
, which is simply string.

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

Tips for accessing the app instance within a module in Nest.js

Currently, I am involved in a project that relies on multiple Nest repositories, approximately 4 in total. Each repository must integrate logging functionalities to monitor various events such as: Server lifecycle events Uncaught errors HTTP requests/resp ...

Do you find this unattractive? What are some ways to improve this unsightly JavaScript statement?

This code seems messy, how can I better structure this switch statement? function renderDataTypeIcon(dataType: string) { let iconName; switch (dataType) { case "STRING": //TODO - ENUM iconName = "text"; break; ...

Unable to locate the module styled-components/native in React Native

When adding types in tsconfig.json to remove TypeScript complaints and enable navigation to a package, the code looks like this: import styled, {ThemeProvider} from 'styled-components/native'; The package needed is: @types/styled-components-re ...

Trigger a class method in an event using Angular with Typescript

I am completely new to TypeScript and Angular, and I am attempting to create a basic drawing component on a canvas. However, I have reached a point where I feel lost and confused about my code. The concept of "this" in TypeScript has been a major stumbling ...

Display issue with React TypeScript select field

I am working with a useState hook that contains an array of strings representing currency symbols such as "USD", "EUR", etc. const [symbols, setSymbols] = useState<string[]>() My goal is to display these currency symbols in a select field. Currently ...

Declare a new variable with a specific data type in TypeScript

I'm working on creating a variable in my component of a specific type, as shown below. myrequest.model.ts export class MyRequest { public endValue: string; public yearEnd: string; } When importing the above into my component, I do the follow ...

Exploring Substrings in TypeScript strings

Can you pass a partial string (substring) as a value to a function in TypeScript? Is something like this allowed? function transform( str: Substring<'Hello world'> ) { // ... } If I call the function, can I pass a substring of that st ...

"Exploring the differences between normalization structures and observable entities in ngrx

I'm currently grappling with the concept of "entity arrays" in my ngrx Store. Let's say I have a collection of PlanDTO retrieved from my api server. Based on the research I've done, it seems necessary to set up a kind of "table" to store th ...

TS2604: The JSX element '...' lacks any construct or call signatures and is unable to be processed

As part of our company's initiative to streamline development, I am working on creating a package that includes common components used across all projects. We primarily work with TypeScript, and I have successfully moved the code to a new project that ...

What is the proper way to utilize RxJS to append a new property to every object within an array that is returned as an Observable?

I'm not very familiar with RxJS and I have a question. In an Angular service class, there is a method that retrieves data from Firebase Firestore database: async getAllEmployees() { return <Observable<User[]>> this.firestore.collectio ...

Delay the execution of a JavaScript method that resolves a promise

Currently, I am delving into the world of Angular 2, typescript, promises, and more. I've set up a small application for developer tools with a service that simply returns hard-coded data. This setup is purely for testing purposes. I want to introduc ...

Invoke the submit function of a form located outside a Material UI dialog from within the dialog

I'm facing an issue with a nested form scenario. The <form/> inside another form is displayed as a Material UI dialog and rendered in a separate portal in the DOM. /* SPDX-FileCopyrightText: 2021 @koistya */ /* SPDX-License-Identifier: MIT */ i ...

Before running any unit tests, I have to address all linting issues as required by ng test

Upon running ng test, the output I receive is as follows: > ng test 24 12 2019 14:20:07.854:WARN [karma]: No captured browser, open http://localhost:9876/ 24 12 2019 14:20:07.860:INFO [karma-server]: Karma v4.4.1 server started at http://0.0.0.0:9876/ ...

What are the steps for running the Dist Folder on a Local Machine in Angular 6 and above?

Currently working on an application with Angular6+. After running the command ng build --prod, a dist folder was generated. How can I view or serve this folder on Localhost? ...

Karma-coverage examines the test coverage of JavaScript files rather than TypeScript files within Angular 2

I am facing an issue with checking test coverage in TypeScript files using Istanbul and setting test thresholds via karma-coverage. The problem arises because karma-coverage checks test coverage in JavaScript files instead of TypeScript, which leads to mis ...

"Debating Angular: Comparing the Use of Getters and Methods in

To prevent cluttering the *ngIf directive with logic directly in the template. <div *ngIf="a === 3 && b === 'foo'"></div> I typically create a custom method like this: public isOk(): boolean { return a === 3 & ...

The concept of passing arguments in Typescript

During my experience with Typescript programming, I encountered a situation like the one described below. If I pass an argument containing an object with the same name as the parameter defined in the function signature, Typescript recognizes it, but not ...

Why is this statement useful? _ equals _;

While studying an Angular 7 class, I stumbled upon the following code that left me a bit confused. It's not exactly a search engine-friendly statement, so my apologies for that :) @Component({ selector: 'app-some', templateUrl: './ ...

What could be causing the malfunction of my Nextjs Route Interception Modal?

I'm currently exploring a different approach to integrating route interception into my Nextjs test application, loosely following this tutorial. Utilizing the Nextjs app router, I have successfully set up parallel routing and now aiming to incorporate ...

What steps can be taken to fix the error message "Type circularly references itself"?

Here's an example of an issue with a predictable outcome: const actionTypes = { name: { set: "name/set", }, } as const; type ActionTypes = { [key: string]: (string | ActionTypes) }; //record value is string or ActionTypes // " ...