Tips for creating a type-safe recursive function

I have a component that allows users to drag and drop files or folders onto it, and my code then processes this information.

Currently, I am working on a recursive method that traverses through folders to collect all the files dropped by the user. The method looks like this:

private traverseDirectory(entry: FileSystemDirectoryEntry): Promise<FileSystemEntry[]> {
    const reader = entry.createReader();
    return new Promise<FileSystemEntry[]>(resolveDirectory => {
      const iterationAttempts: Promise<FileSystemEntry>[] = [];
      const errorHandler = () => {
        logger.error('An error occurred while traversing the directory.');
      };

      const readEntries = () => {
        reader.readEntries((batchEntries: FileSystemEntry[]) => {
          if (!batchEntries.length) {
            resolveDirectory(Promise.all(iterationAttempts));
          } else {
            batchEntries.forEach((batchEntry: FileSystemEntry) => {
              if (batchEntry.isDirectory) {
                iterationAttempts.push(
                  this.traverseDirectory(batchEntry as FileSystemDirectoryEntry)
                );
              } else {
                iterationAttempts.push(Promise.resolve(batchEntry));
              }
            });
            readEntries();
          }
        }, errorHandler);
      };
      readEntries();
    });
  }

I am looking for suggestions on how to improve the readability and cleanliness of this code, especially in removing the "as any" part from after the isDirectory() condition. Any help would be greatly appreciated!

As I am relatively new to Angular, any advice on enhancing my coding skills in general would also be very welcome. Thank you! :)

Answer №1

Steer clear of the Promise constructor antipattern! Opt for promisifying just the readEntries method itself, and then leverage promise chaining or the more streamlined async/await:

private async traverseDirectory(directory: FileSystemDirectoryEntry): Promise<FileSystemFileEntry[]> {
  const reader = entry.createReader();
  const dirEntries = await new Promise<FileSystemEntry[]>((resolve, reject) => {
    reader.readEntries(resolve, reject);
  });

  const result: FileSystemFileEntry[] = [];
  for (const entry of dirEntries) {
    if (entry.isDirectory) {
      result.push(...await this.traverseDirectory(entry));
    } else if (entry.isFile) {
      result.push(entry);
    } else {
      console.warn(`Ignoring unsupported entry at ${entry.fullPath}`);
    }
  }
  return result;
}

Answer №2

Take note that the function you are using returns a Promise<FileSystemEntry[]>, which means it returns a list of file entries. However, the type signature of the list you are trying to add this promise to is Promise<FileSystemEntry>[] (a list of promises). Because the types are different, you will need to cast it to any. Make sure to adjust the type of your list accordingly.

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

How can I store the data retrieved from an API and then forward it to a URL using Angular?

Is there a way to save and pass the data received from an API to a URL in Angular? SERVICE.ts readonly apiUrl = 'http://localhost:49940/'; constructor(private http: HttpClient) { } getUserName(): Observable<any> { return this.http.ge ...

What limitations do we face when trying to change the objects received by a component through @input() in Angular?

Recently, I made the leap from angular 7 to angular 11 in my app. Everything was running smoothly until I decided to incorporate angular universal for server-side rendering. Shortly after implementing server-side rendering, a flurry of errors cropped up, ...

Failure to trigger VS code extension functionality

After much thought, I've decided to embark on creating my own VS Code extension specifically for TypeScript/Angular code snippets. The first snippet I've developed is called Forloop.snippet: const ForLoopSnippet = 'for (let {{iterator}} = { ...

The attribute 'X' is not present in the specified type 'IntrinsicAttributes & InferPropsInner'

I've been restructuring my code from a .js file to a .tsx file, as seen below: import React, { useEffect, useState } from 'react' import PropTypes from 'prop-types' import { checkMobile } from '../../utils/common' import ...

Having trouble with a 'Could not find a declaration file for module' error while using my JavaScript npm package?

I recently released a JavaScript npm package that is functioning properly. However, when importing it into another application, there always seems to be three dots in front of the name, along with an error message that reads: Could not find a declaration f ...

Angular 6 and Typescript: How to Map Objects in Arrays within Arrays

We currently have two arrays named speisekarte (consisting of 10 objects) and essensplan (containing 8 objects). const speisekarte = [ { id: 11, name: 'Kabeljaufilet', price: 3.55, type: 'with fish' }, { id: 12, name: 'Spaghet ...

Failure in retrieving values from AngularFire2 Subscribe

I am encountering an issue with the code in my authService constructor( private afAuth: AngularFireAuth, private db: AngularFireDatabase, private router: Router ) { this.authState = afAuth.authState; this.authState.subscribe((use ...

The ngOnInit function is not triggered upon instantiation of an Injectable class

What could be causing the ngOnInit() method not to be called upon resolution of an Injectable class? Code import {Injectable, OnInit} from 'angular2/core'; import { RestApiService, RestRequest } from './rest-api.service'; @Injectable ...

Continuously receiving unhandled promise rejection errors despite implementing a try-catch block

Every time I run my code, I encounter the following issue: An UnhandledPromiseRejectionWarning is being thrown, indicating that a promise rejection was not properly handled. This can happen if you throw an error inside an async function without a catch bl ...

Issues with the rating plugin functionality in Ionic 3

After following the instructions in this tutorial: http://ionicframework.com/docs/native/app-rate/ Even though I implemented the second method, I encountered the following error: Uncaught (in promise): TypeError: Cannot read property 'split' ...

Check the type of the indexed value

I need help with a standard interface: interface IProps<T> { item: T; key: keyof T; } Is there a way to guarantee that item[key] is either a string or number so it can be used as an index for Record<string | number, string>? My codeba ...

"An error will be thrown if attempting to add experimental support for decorators when creating a

Attempting to create a new module in an Angular project using the command: ng g module core/employee-applicant --routing=true Results in an exception being thrown for the newly generated module. An error message stating, "Experimental support for decor ...

The type 'string' is not a valid index for the type 'Partial<NewData>'

Can someone help me resolve this issue? https://i.sstatic.net/GkFYf.png I am looking to encase each object field from the getters argument in a ComputedRef wrapper import { computed, ComputedRef } from "vue"; function useComputedGroup<T exte ...

What is the quickest way to send a message with just one press of the Enter key

Whenever I press "Enter Keyword," the message should be sent instead of going to the next line. ...

Rollup does not allow the use of self-written component imports in a component library

I am in the process of creating a personalized component library using my own components. However, I am encountering difficulties in the final stage of constructing the library using rollup. The current structure of my folders is as follows: ├── src ...

The use of p-message in Angular's PrimeNg library is not permitted

Hey there, I'm having a bit of trouble with the p-message Tag in Angular. I believe I've imported it correctly as shown below. import { MessageModule } from 'primeng/message'; imports: [ .... MessageModule, ... In the ...

Describing a property of an interface as the determined form of a conditional type that is generic

I am currently working on defining an interface that includes a method with a conditional function definition. For example: interface Example<T> { func: T extends string ? () => string : () => number; } class ExampleClass<T extends str ...

Understanding the connection between two unions through TypeScript: expressing function return types

Within my codebase, I have two unions, A and B, each with a shared unique identifier referred to as key. The purpose of Union A is to serve as input for the function called foo, whereas Union B represents the result yielded by executing the function foo. ...

The Ghostly Glare of Doom: Ionic 2 Strikes on Android

While my application runs smoothly in the browser, I encounter an error when trying to run it on my device. The issue is as follows: 0 758771 log deviceready has not fired after 5 seconds. 1 758797 log Channel not fired: onDOMConte ...

In Electron, methods for detecting and resolving Error TS2304: Unable to locate the name 'unknown on(event: 'ready', listener: (launchInfo: unknown) => void): this are essential for smooth operation

Encountering an issue while running npm build. Electron version: 7.1.2 TypeScript version: ^2.5.1 Target version: ES2017 Here are the details of the error. When I performed the build under the following conditions: Electron version: 6.0.0 TypeScript ver ...