Identifying one of the two possible return types automatically

In my code, there is a function named isDone() that will return data from either an array of hashes or a dictionary of hashes:

public async isDone() {
  this.startDelayedTasks();
  await Promise.all(this._tasks);
  const hadErrors = this._failed.length > 0 ? true : false;
  if (hadErrors) {
    throw new ParallelError(this);
  }
  return this._resultType === "hash"
    ? (this._results as IDictionary<T>)
    : hashToArray<IParallelArrayType<T>>(this._results) as IParallelArrayType<T>[];
}

The interface for IParallelArrayType looks like this:

export interface IParallelArrayType<T> {
  name: string;
  value: T;
}

If consumers request the array type, they might want to use functions like map, filter, or length. However, since the return type could be different, it can lead to errors like this:

https://i.sstatic.net/0Lvhl.png

To work around this issue, consumers can add a check like this:

if(Array.isArray(results)) {
  expect(results.length).to.equal(4);
}

It would be helpful if there was a way to avoid burdening the consumer with handling this. One idea could be implementing a tagged union type and using a Symbol for identifying the property.

This approach seems promising, but I also want to make sure that consumers of the hash/dictionary return type do not see the Symbol key when iterating through the object using Object.keys(dictionary). Is there a solution to achieve this, or am I delving too deep into the runtime environment?

Answer №1

Just wanted to provide an update in response. Your proposed solution entails that the consumer must validate or confirm that the returned value is indeed an array rather than a dictionary.

To alleviate this burden for the consumer, one approach is to ensure that the fluent interface type changes after calling returnAsArray(), transitioning to a version of the type that guarantees isDone() will return an array. However, TypeScript does not support altering the object's type directly, so it's recommended to return a different object altogether. Below is a simplified code snippet to illustrate this concept:

type Dictionary<T> = { [k: string]: T }
type EntryArray<T> = { k: string, v: T }[];
type ResultType<T> = {
  dict: Dictionary<T>;
  array: EntryArray<T>;
}

In this setup, two result types are defined along with a mapping from the strings "dict" and "array" to their respective types. Subsequently, we define our fluent class as follows:

// FluentThing class implementation

By using this method, the consumer can avoid unnecessary checks or assertions. It provides a clear distinction between returning a dictionary or an array. This ensures convenience and accuracy for the consumer.


It's crucial to note the importance of returning a new object instead of mutating the existing one. Mutating the current object may lead to unexpected behavior, especially if consumers attempt to reuse intermediate values throughout the process.


Additionally, delaying the decision on whether the results should be returned as an array or dictionary until the data is actually retrieved can simplify the interaction for both the consumer and the type system.

Overall, the goal is to streamline the process and enhance clarity for consumers interacting with the fluent interface. Good luck with your implementation!

Answer №2

Did you know that Typescript allows for type unions to be used with methods as well? By leveraging this feature, you can create functions that return one of two possible types based on user input.

class Bar {
    data1: string = 'sample text';
    data2: number = 5;
    baz(arg: string | number): string | number {
        return arg;
    };
}

let bar = new Bar();
let result1 = bar.baz(bar.data1);
let result2 = bar.baz(bar.data2);
console.log(result1); //sample text
console.log(result2); //5

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

What steps can I take to eliminate the overload error that occurs when I extend the Request object in Express?

I'm having trouble extending Express' Request object to access req.user, and I'm encountering an overload error. I've attempted a couple of solutions, but none of them seem to work for me. EDIT: I am currently using Passport.js and JWT ...

What are the reasons behind the issues encountered when enabling "Optimization" feature in Angular that affect the proper rendering of PrimeNg elements?

Angular Version : 9.x Primeng Version : 9.x We've encountered an issue with PrimeNg elements not rendering correctly in our dev/prod environments, although they work fine in the local environment. After some investigation, we found that the culprit ...

Retrieve the Ionic storage item as a string

My issue is related to the code snippet below: this.storage.get('user') Upon execution, it returns the following object: t {__zone_symbol__state: null, __zone_symbol__value: Array(0)} I am uncertain about how to handle this object. Is there ...

Is there a way for me to receive a unique selection of items from an array for every accordion item?

I am currently facing an issue where all three accordion items have the same set of objects, but I want each of them to have a different set. Here's what I have attempted so far, but it is not working as expected: const meetingRooms = [ { ...

Assign a class to a button created dynamically using Angular

While working on my project, I encountered an issue where the CSS style was not being applied to a button that I created and assigned a class to in the component.ts file. Specifically, the font color of the button was not changing as expected. Here is the ...

MUI DataGrid Identifying Duplicate Rows

I'm encountering an issue with my Data Grid component from MUI when fetching data using axios. The console shows the correct data, but on the page, it only displays one result or duplicates. I suspect there might be a frontend problem, but I'm s ...

How can one execute a function within an HTML attribute value using Angular?

I am currently attempting to use the weatherToFontAwesomeIcon(weatherDescription: string) function directly within the HTML file for this component. My goal is to showcase a specific FontAwesome icon based on the weather response from the API. import { Cur ...

The value returned by Cypress.env() is always null

Within my cypress.config.ts file, the configuration looks like this: import { defineConfig } from "cypress"; export default defineConfig({ pageLoadTimeout: 360000, defaultCommandTimeout: 60000, env: { EMAIL: "<a href="/cdn-cgi/ ...

Error alert: TypeScript typings issue - Naming conflict with Promise / Failure to locate name Promise

I am currently working on a client/server JavaScript application and I am facing a significant issue with Promises. It appears that they are either undefined or duplicated, and this problem seems to be related to the @types package. npm install --save @ty ...

Is there a way to execute the run function of a different Component in Angular 7 without causing the current

Is there a way to execute the ngOnInit() function from one component inside another component without needing to refresh the existing page? ...

An issue occurred in the modal window following the relocation of project files

I encountered an issue with the modal in my Nativescript project after rearranging a few project files, including the modal. I updated the imports and deleted any compiled JavaScript files to ensure that my project could recompile correctly. Although I&ap ...

What is the approach taken by this component to display its child elements?

While delving into the code of react-accessible-accordion, I found myself puzzled by the way it handles rendering its children. The snippet below is from Accordion.tsx: export default class Accordion extends React.Component<AccordionProps> { // ...

When compiling my TypeScript file, I encountered an error stating that a block-scoped variable cannot be redeclared

In my Visual Studio Code, I have written just one line of code in my ex1.ts file: let n: number = 10; Upon compiling using the command tsc ex1.ts, the compiler successfully generates the ex1.js file. However, VSC promptly displays an error in the .ts file ...

What makes FC function components stand out from traditional vanilla React function components?

I recently came across this FC function component: const LabelForm: FC<LabelFormProps> = ({ labels, selectedID, }) => { const selectedLabel = selectedID !== undefined && labels[selectedID]; In my usual implementation, I do it like t ...

Troubleshooting: Angular 6 Renderer2 Issue with Generating Dynamic DOM Elements for SELECT-Option

Currently, I am attempting to dynamically create a select option using Renderer2. Unfortunately, I am facing difficulties in creating the <Select></Select> element, but I can confirm that the <options> are being successfully created. Due ...

The Jest type definitions seem to be malfunctioning in this TypeScript project

Recently, I began a new Typescript project utilizing GTS. While the typings are functioning correctly for regular *.ts files, I am encountering difficulties in getting *.spec.ts files to work. Issue Each jest function is being flagged as red by ESLint wit ...

Tips for utilizing the "this" keyword in TypeScript

As a newcomer to TypeScript, I am seeking assistance on how to access the login service within the authenticate function. Despite using the 'this' keyword to retrieve the login service, it seems ineffective. Additionally, I find myself puzzled by ...

What are the steps for implementing persisting and rehydrating data in redux-toolkit?

After setting up the redux-persist with react-toolkit as recommended in the documentation, I found myself needing to perform some operation on rehydrate. Unfortunately, my attempts have been unsuccessful so far. Here is what I have tried: ... import { RE ...

What is the proper way to specify the interface as Dispatch<Action>?

My goal is to create an interface with the dispatch function without using Redux. interface DispatchProps { dispatch: (action: { type: string }) => void; } export function addTwoToNumber({ dispatch }: DispatchProps) { dispatch({ type: '@addTwo ...

Unable to perform a default import in Angular 9 version

I made adjustments to tsconfig.json by adding the following properties: "esModuleInterop": true, "allowSyntheticDefaultImports": true, This was done in order to successfully import an npm package using import * as ms from "ms"; Despite these changes, I ...