Automatic type inference is activated while employing intricate "isEmpty" verification

I have created a customized function similar to Ramda's isEmpty, tailored to meet my specific requirements:

/**
 * Checks if a value is empty.
 * Returns true for null, undefined, empty strings, empty Sets, empty Maps, and objects without properties.
 * @param input Can be any type of value.
 * @example
 *
 *     isEmpty([1, 2, 3]); //=> false
 *     isEmpty([]); //=> true
 *
 *     isEmpty(''); //=> true
 *
 *     isEmpty(null); //=> true
 *     isEmpty(undefined); //=> true
 *
 *     isEmpty({}); //=> true
 *
 *     isEmpty(new Set([1, 2, 3])); //=> false
 *     isEmpty(new Set()); //=> true
 *
 *     isEmpty(0); //=> false
 *
 *     isEmpty(new Date()); //=> true
 *     isEmpty(Date.now()); //=> false
 */
export const isEmpty = (input: any): boolean => {
  const isMapOrSet = input instanceof Map || input instanceof Set;
  return input === null
    || input === undefined
    || (input instanceof String ? input.length > 0 : false)
    || (isMapOrSet ? input.size === 0 : false)
    || (!isMapOrSet && input instanceof Object ? Object.keys(input).length === 0 : false);
};

While using this function is straightforward, I find the boolean return type problematic as TypeScript struggles to infer null checks provided by the function.

For instance, the following code is valid but TypeScript raises a warning about potential null at the someResult[0] call.

const someResult: [] | null = getStuffFromAPI();
const x = isEmpty(someResult)
? {}
: someResult[0]; // TypeScript alerts about possible _null_ here.

Hence, my question is: How can I enhance the function's signature to help TypeScript accurately deduce the return type?

I attempted to define a custom return type using conditional types, yet I struggled to implement it correctly.

To provide clarity on what I seek, here's some pseudo code (please note that HasNoElements and IsEmpty are not real in TS):

type IsEmpty<T> =
  T extends null | undefined ? true :
  T extends Map & HasNoElements ? true :
  T extends Set & HasNoElements ? true :
  T extends String & IsEmpty ? true :
  T extends Object & IsEmpty ? true :
  false;

I might be overcomplicating things, but I wish to expand my knowledge in this area.

Answer №1

Thanks to the enhanced type inference for generics in TypeScript 3.4, the issue has been successfully resolved. Now, as demonstrated in my example earlier, I effortlessly obtained all the accurate type signatures I needed.

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

Configuring global runtime variables in NextJS for server-side operations

Currently, I am utilizing the instrumentation.ts file in NextJS to retrieve configuration dynamically when the server starts up. My goal is to have this configuration accessible during runtime for all API routes and server-side components. What would be th ...

Establishing a Recyclable Testing Rendering Method in redux toolkit version 2

In the era of Redux Toolkit v2, a noticeable change occurred with the absence of the EmptyObject type and the unavailability of the PreloadedState type in the @reduxjs/toolkit package. This has led to a requirement of defining all reducers inside the pre ...

Best practice for entering events in callback

Recently, I delved into Angular because I anticipate needing to use it down the line. My current focus is on studying components communication, particularly from child to parent. I came across various methods of achieving this. In each example, the ChildC ...

CompositeAPI: Referencing HTML Object Template - Error TS2339 and TS2533 when using .value to access Proxy Object

Having trouble referencing an element in VueJS 3 CompositeAPI. In my current implementation, it looks like this: <div ref="myIdentifier"></div> setup() { const myIdentifier = ref(null); onMounted(() => { console.log(myIden ...

Tips on reordering modules in typings.json

Utilizing typings for loading type definitions. In my project, I am utilizing bluebird as the promise implementation. The following lines are present in my typings.json: "Promise": "github:DefinitelyTyped/DefinitelyTyped/bluebird/bluebird.d.ts#dd328830ddd ...

Expanding upon React Abstract Component using Typescript

Currently, I am in the process of building a library that contains presentations using React. To ensure consistency and structure, each presentation component needs to have specific attributes set. This led me to create a TypeScript file that can be extend ...

Using Long Polling with Angular 4

I am looking for a way to monitor the progress of a certain task using API calls. To achieve this, I have developed a service that executes these API calls every 1.5 seconds Main Component private getProgress() { this.progressService.getExportPr ...

Completing a fetch promise and sending the outcome to a function that is not awaited

I have a function that retrieves data from a Postgresql database and returns it. The expected behavior is to fetch the data using the async function getCat(), process it in const Catalogue, and then return it to a ReactJS component. catalogue.tsx: import ...

Breaking down an object using symbols as keys in Typescript

I'm encountering an error when running this code Type 'symbol' cannot be used to index type '{ [x: string]: string; }'.: let symbol = Symbol() let obj = { [symbol] : 'value'} let { [symbol]: alias } = obj // ...

How can one identify the optional fields in TypeScript interfaces generated from GRPC proto-files?

Within my ts-node project, I am converting TypeScript from gRPC proto files, where certain properties are denoted as optional. However, the resulting TS interfaces end up with ALL properties being marked as optional. Additionally, an extra "_" prefixed pr ...

When using html2canvas in Angular, it is not possible to call an expression that does not have a call signature

I'm currently working on integrating the html2canvas library into an Angular 8 project. Despite trying to install the html2canvas types using npm install --save @types/html2canvas, I'm still facing issues with its functionality. Here's how ...

Troubleshooting: The issue of importing Angular 2 service in @NgModule

In my Angular 2 application, I have created an ExchangeService class that is decorated with @Injectable. This service is included in the main module of my application: @NgModule({ imports: [ BrowserModule, HttpModule, FormsModu ...

MSBUILD encounters numerous JQuery errors when compiling a web project with TypeScript

Currently, I am working on a .net core 3.1 (netcoreapp3.1) razor pages project that includes typescript files and a few javascript files. The project builds perfectly from Visual Studio 2019 (professional) as well as from the command line using MSBuild. H ...

Utilize generic typings to interact with the Array object

I'm facing a challenge in developing an interface that is dependent on another interface. Everything was going smoothly until I reached the Array of Objects. Let me elaborate, I have an 'Entity' that defines how a document is stored in a ...

Find the distinct values from an array of objects containing varying elements using Typescript

My array contains dynamic elements within objects: [ { "Value1": [ "name", "surname", "age" ], "Value2": [ "name" ...

Guidance on showcasing the current day's weekday name through TypeScript

I am perplexed about how to begin in TypeScript after successfully setting up the display using gate. ...

Invoke the built-in matcher within a Playwright custom matcher

I am in the process of implementing a custom matcher for Playwright based on the information provided in the official documentation on extending expect. In a similar vein to this unanswered discussion, my goal is to invoke an existing matcher after modifyi ...

Typescript: Select just one option from the union

There is a specific Query type that contains the getBankAccounts property: export type Query = { getBankAccounts: GetBankAccountsResponseOrUserInputRequest, }; This property can return either a GetAccountsResponse or a UserInputRequest: export type Ge ...

What is the process of extending a class in TypeScript?

I have a few services that contain the same code: constructor (private http: Http) { //use XHR object let _build = (<any> http)._backend._browserXHR.build; (<any> http)._backend._browserXHR.build = () => { let _xhr = _ ...

In what situations might a finally block fail to execute?

Are there any circumstances where the code in a finally block may not be reached, aside from the usual suspects like process exit(), termination signal, or hardware failures? In this TypeScript code snippet that usually runs smoothly in node.js, occasiona ...