Filling a data entry with simultaneous commitments

Sample code:

type Alphabet = 'a' | 'b' | 'c';

const alphabetMap: Record<Alphabet, null> = { 'a': null, 'b': null, 'c': null}

// Select any asynchronous processing function you prefer
function asyncRandomize(): Promise<number> {
    return new Promise(resolve => setTimeout(() => resolve(Math.random()), 1000))
}

const randomizedValues: Promise<Record<Alphabet, number>>> = Promise.all(
    Object.keys(alphabetMap).map((letter: Alphabet) => 
        asyncRandomize()
            .then((value): [Alphabet, number] => [letter, value])
    )
)

Is there a way to convert randomizedValues to have type

Promise<Record<Alphabet, number>>
instead of
Promise<[Alphabet, number][]>
without using any?

Answer №1

To tackle this issue, you might need a function that mimics the behavior of Object.fromEntries(). However, when it comes to TypeScript typings for such a function, it may end up being too general for your specific requirements. You could potentially receive a type like Record<string, number> instead of Record<I, number>. If you are comfortable with using type assertions, you can opt for that approach:

const irandomized  = Promise.all(
   (Object.keys(is) as I[]).map((i: I) =>
      asyncRandomize()
         .then((v): [I, number] => [i, v])
   )
).then(z => Object.fromEntries(z)) as Promise<Record<I, number>>;

Avoiding the usage of any in this scenario is crucial.


If you prefer not to rely on type assertions within your code, one alternative is to create your custom function akin to Object.fromEntries(), but with more specific typings (keeping in mind that some form of type assertion needs to exist inside the function's implementation). Here's a potential function that might align better with your needs:

type Entry = readonly [PropertyKey, any];
type ExtractSupertype<T, U> = T extends any ? [U] extends [T] ? T : never : never;
function fromEntries<E extends readonly Entry[]>(entries: E): {
   [K in E[number][0]]: ExtractSupertype<E[number], readonly [K, any]>[1] // TS 4.0-
   // [K in E[number] as K[0]]: K[1] // TS 4.1+, easier syntax
} {
   const ret: any = {};
   for (let entry of entries) {
      ret[entry[0]] = entry[1];
   }
   return ret;
}

It's worth noting that once TypeScript 4.1 is released and introduces mapped type as clauses, the ExtractSupertype construct will become redundant.

You can encapsulate this functionality in a separate library. The primary aim is for fromEntries() to convert a strongly-typed array or tuple of entries into a strongly-typed object:

const foo = fromEntries([
   ["x", Math.random()], ["y", new Date()], ["z", Math.random() < 0.5]
] as const);
/* const foo: {
    x: number;
    y: Date;
    z: boolean;
} */

This method ensures that you obtain specific properties associated with distinct types, rather than just receiving a generic

Record<string, number | Date | boolean>
.

Armed with this function, you can proceed without resorting to unsafe type assertions:

const iKeys = ["a", "b", "c"] as const;
const irandomized = Promise.all(
   iKeys.map((k) =>
      asyncRandomize()
         .then(v => [k, v] as const)
   )
).then(fromEntries);

The modification made involved replacing is with an array of its keys. Since no operation was being performed on the values, leveraging Object.keys(is) returned a type of string[] instead of

I[]</code. To simplify things, a strongly-typed tuple of keys was utilized directly.</p>
<p>You can now verify that the output of <code>irandomized
matches your expectations:

/* const irandomized: Promise<{
    a: number;
    b: number;
    c: number;
}> */

Furthermore, confirming its runtime behavior is equally important:

irandomized.then(e => console.log(JSON.stringify(e)));
// {"a":0.9961594084980729,"b":0.015675814053288217,"c":0.1783156372032898}

Playground link for the 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

Error in TypeScript in VSCode when using the React.forwardRef function in a functional component

We are developing our component library using JavaScript instead of TypeScript. In our project's jsconfig.json file, we have set checkJs: true. All components in our library are functional and not based on class components. Whenever a component needs ...

The system encountered difficulty handling a recursive structure

I am facing a challenge with a recursive JSON structure that needs to be stored as a series of maps with keys. The structure comprises flows and subflows that have references to each other. Here are the type declarations, noting that the issue lies in the ...

Unlock the power of Angular Component methods even when outside the Angular library with the help of @ViewChild()

In my Angular library, there is a component called AComponent which has its own template, methods, and properties. Once the Angular library is packaged, it becomes available as a NuGet package for other projects to utilize. @Component({ selector: ' ...

Deriving variable function parameters as object or tuple type in TypeScript

Searching for a similar type structure: type ArgsType<F extends Function> = ... which translates to ArgsType<(n: number, s: string)=>void> will result in [number, string] or {n: number, s: string} Following one of the provided solu ...

Leveraging the outcome of an Observable in one method with another Observable in Angular2

The issue at hand I am facing difficulty in utilizing the value returned by the Observable from getUserHeaders() within my http.get request. Error encountered Type 'Observable<void>' is not assignable to type 'Observable<Particip ...

Specifying the return type of a function as a combination of the types of the input arguments

Is there a way to safely implement the given function in TypeScript without using unsafe casts or an extensive number of function overloads with various input permutations? interface Wrapped<T> { type: string; data: T; } interface WrappedA&l ...

Deducing the return type of asynchronously generated functions

My expectation is to automatically determine the return type of async functions when they are yielded as values from a generator. In the following example, the inference of the type of the yielded async functions appears to work correctly (detected as () ...

How can Angular developers properly implement token refreshing in their applications?

Recently, I've been struggling with implementing a logic in my code. I have a specific requirement: Whenever there is a signed request (signed - means it has a JWT token for authenticated users) made to the API backend, the API backend may respond w ...

Adding an object to an array in Postgres with TypeORM

I am currently facing an issue with the column in my Postgres database that has a data type of json. The code snippet for this scenario is as follows: @Column({ type: 'jsonb', nullable: false, default: [] }) us ...

There was an issue while attempting to differentiate '[object Object]'. Ionic only allows arrays and iterables for this operation

I am looking for a way to extract all the "friend" objects from a JSON response and store them in an array so that I can iterate through them on an HTML webpage. ...

Using Moment JS to display the days of the upcoming week

I'm in the process of developing a weather application and I need to create code that will display the upcoming week's weather forecast. The only information I have from the server is a "time" entity with a "value" set for next Monday such as "20 ...

Angular - Using HttpClient for handling POST requests

The example provided in the official Angular HttpClient documentation demonstrates how to make a POST request to a backend server. /** POST: add a new hero to the database */ addHero (hero: Hero): Observable<Hero> { return this.http.post<Hero&g ...

Comparable to LINQ SingleOrDefault()

I frequently utilize this particular pattern in my Typescript coding: class Vegetable { constructor(public id: number, public name: string) { } } var vegetableArray = new Array<Vegetable>(); vegetableArray.push(new Vegetable(1, "Carrot")); ...

Modifying the value upon saving in Adonis JS model

Using Adonis js I am facing an issue when trying to convert an ISO string to Datetime while saving data (the opposite of serializing DateTime fields to ISO string). I cannot find a way to do this in the model, like I would with a mutator in Laravel. Whene ...

The Firebase EmailPasswordAuthProvider is not a valid type on the Auth object

When working in an Angular2/TypeScript environment, I encountered an error when trying to use the code provided in the Firebase documentation. The error message displayed was "EmailPasswordAuthProvider Does Not Exist on Type Auth". var credential = fireba ...

Discovering class methods in typescript

Currently, I am running TypeScript unit tests using Mocha Chai after configuring the compiler options to ts-node. Within one of my unit tests, I am seeking a way to retrieve all methods from a utility class that I have designed and execute the same set of ...

issues arise post-transpilation with creating errors

In order to practice, I decided to create a basic TypeScript project. If it could be helpful, here is my ts.config: { "compilerOptions": { "target": "es2016", "module": "commonjs", "outDir": "./dist", "esModuleInterop": true, "forceC ...

Establishing a typescript class as an interface

While attempting to upgrade to TypeScript 3.5, I ran into an issue with a signature that has been overlooked by the ts-compiler, despite being present for years. A third-party framework (knockoutJS) requires me to pass something that adheres to this: int ...

How to Pass a JSON Object to a Child Component in Angular and Display It Without Showing "[Object

Need help with my API call implementation. Here's a snippet from my Input component: Input.html <form (submit)="getTransactions()"> <div class="form-group"> <label for="exampleInputEmail1"></label> <input type="t ...

How can I adjust the column width in OfficeGen?

Currently, I am utilizing officeGen for the purpose of generating word documents. <sup> let table = [ [ { val: "TT", fontFamily: "Times New Roman", }, { val: "Ten hang", ...