Determining the return type within a nested object using TypeScript

This is largely a continuation of a previous inquiry on a related theme, albeit with some simplification.

The main goal here is to pass an object's attributes and values through a conversion function (which will eventually be a factory builder) and then assign those modified properties to the returned object while also preserving the data types.

Below is the snippet of code I've been working on:

type Config<T extends {[key:string]: number | string}> = {
    inst?: T
}

function convert ( value: string ): number;
function convert ( value: number ): string
function convert( value: any ): any {
    if ( typeof value === 'number' ) {
        return value.toString();
    }

    return parseInt( value.toString(), 10 );
}

function init<T extends {[key:string]: any}>(db, config: Config<T>): T & {} {
    let ret: any = {};

    if ( config.inst ) {
        for (let [key, value] of Object.entries(config.inst)) {
            let res = convert( value );
            ret[ key ] = res;
        }
    }

    return ret;
}


let a = convert( '1' ); // `a` now holds a `number`
let b = convert( 2 );   // `b` now contains a `string`

let { strToNum, numToStr } = init( null, { inst: { strToNum: '1', numToStr: 2 } } );
// `strToNum` is a string - but expected to be a number
// `numToStr` is a number - when it should be a string

The convert function seems to be functioning correctly with its overload type, however, implementing the desired typing for the returned object's parameters has proven challenging. Any thoughts or suggestions?

Answer №1

If you're looking to merge conditional types with mapped types in TypeScript, you can use the following approach:

type Convert<T extends string | number> = T extends number ? string : number;
declare function initialize<T extends { [key: string]: any }>(
  database: any, 
  configuration: Config<T>
): {[K in keyof T]: Convert<T[K]>};

Here's how you can test it out:

let { strToNum, numToStr } = initialize(null, { inst: { strToNum: '1', numToStr: 2 } });
strToNum.toFixed(0);  // works fine
numToStr.charAt(0); // also works fine

Looks promising.


Additionally, you can utilize the conditional type for your convert() function instead of using multiple overloads:

function convert<T extends string | number>(value: T): Convert<T>;
function convert(value: string | number): string | number {
  if (typeof value === 'number') {
    return value.toString();
  }
  return parseInt(value.toString(), 10);
}

convert(Math.random() < 0.5 ? "1" : 2); // string | number
// the above will fail with overloads

I hope this explanation proves beneficial to you. Best of luck!

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

Having trouble connecting to remote databases such as Supabase, MongoDB Atlas, or Neon DB using the Prisma ORM

I've encountered the same issue across all my projects. Everything runs smoothly when I work with local databases like postgres or mongodb (within a docker container on my machine). However, connecting to remote databases such as mongo db atlas, supab ...

Typescript: The type 'X' does not correspond with the signature '(prevState: undefined): undefined' in any way

My React Native app, which is written in TypeScript, has been giving me a hard time with an error lately. The issue revolves around a Searchable List feature. This list starts off with an Array of values and gets updated when users type into a search bar. ...

Running Jest tests concurrently causes a TypeError due to converting a circular structure to JSON

While running Jest Tests in parallel, I encountered the following error. Interestingly, when running each test individually or using --RunInBand, they all pass without any issues. Test suite failed to run Jest worker encountered 4 child process except ...

What is the method for updating a property in an object of a Typescript class?

I am trying to work with a Fruit class: export class Fruit { constructor(public id: number, public name: string) {} public changeName(_name: string): void { console.log('changing name') this.name = _name } } My imple ...

In order to load an ES module, specify the "type" as "module" in the package.json file or utilize the .mjs extension

I attempted to run this vscode extension repository on my desktop. After cloning it locally, I ran npm install Upon pressing f5 in the vscode editor, an error occurred: Process exited with code 1 (node:1404) Warning: To load an ES module, set "type": "mo ...

I attempted to unsubscribe from an observable in Angular, but I encountered an error stating that the unsubscribe function does not exist

Here is the code snippet from a components.ts file in an Angular project. I encountered the following error during compilation: ERROR merge/merge.component.ts:75:12 - error TS2551: Property 'unsubscribe' does not exist on type 'Observable& ...

Analyzing elements within an array using Angular 4

I have an array filled with various Objects such as: [ {"id":1,"host":"localhost","filesize":73,"fileage":"2018-01-26 09:26:40"}, {"id":2,"host":"localhost","filesize":21,"fileage":"2018-01-26 09:26:32"}, {...} ] These objects are displayed in the fol ...

Invoke method from service on click in Angular 2

I'm facing an issue with a button component that should trigger a function on click event: <button pButton type="button" label="Add EchoBeacon" (click)="insertPoint()"> constructor(private mappaService: MappaService) {} ... insertPoint() { ...

The compatibility issue arises when trying to utilize Axios for API calls in Ionic 6 React with react-query on a real Android device in production. While it works seamlessly on the emulator and browser

My form utilizes react-hook-form to submit data to a server. Here is the code: <FormProvider {...methods}> <form onSubmit={handleSubmit(onIndividualSignup)}> <Swiper onSwiper={(swiper) => setSlidesRef(s ...

Utilizing ES6 class methods as a parameter for Express routing

I'm having trouble passing a class method as an Express route parameter. I've attempted to bind the method and also tried using arrow functions, but neither approach has worked for me. My project involves TypeORM, and I keep encountering the err ...

Expanding the capabilities of the Express Request Object using TypeScript

Looking to enhance the Request object of express with a new property To start, create a middleware that verifies the session and token containing the companyId import { verifyToken } from '../utils/jwt/jwt'; declare module 'express-serve-s ...

If every single item in an array satisfies a specific condition

I am working with a structure that looks like this: { documentGroup: { Id: 000 Children: [ { Id: 000 Status: 1 }, { Id: 000 Status: 2 ...

Can you help me troubleshoot an issue I am facing with the expand table in Angular 9 and JS? I am getting an

Here you can find the code demonstration and behavior: No extensive explanation is necessary. Check out the StackBlitz demo by clicking on the first row to view its details. Then, click on the second row to see how the details from the first row are repl ...

Warning users before navigating away from a page with an incomplete form (Code restructuring)

Creating a code that alerts the user when they have any "unsaved" form in the View Check out this script: import { __ } from "./translation"; export class Unsave { private unsaved: boolean = false; public register(): void { $(":button, ...

Hold on for the processing of a CSV document

I am attempting to utilize the "csv-parse" library in Typescript to read a csv file by creating an observable. The code provided uses fs.createReadStream to read the file. I am looking to return the observable and subscribe to it, but it seems that the p ...

Update my SPFx web component to link to a CSS file instead of embedding the CSS styles directly within the component

I recently developed a web part that is reminiscent of a similar one found on GitHub @ https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-enhanced-list-formatting. This particular web part enables the embedding of custom CSS code directly in ...

typescriptIs it possible to disregard the static variable and ensure that it is correctly enforced

I have the following code snippet: export class X { static foo: { bar: number; }; } const bar = X.foo.bar Unfortunately, it appears that TypeScript doesn't properly detect if X.foo could potentially be undefined. Interestingly, TypeScript ...

What is the method for adding pages to the ion-nav component in Ionic with Angular?

How can I implement a UINavigationController-like functionality in iOS using an ion-nav element? The example provided here is in Javascript, but I need assistance with implementing it in Angular. Specifically, I'm unsure of how to programmatically add ...

Exploring the power of Vue3 with reactive nested objects and the inclusion of

It seems like I've encountered a bit of a challenge... Perhaps a bug in Vue3 with Typescript and the composition API, or maybe I'm missing something. I'm facing an issue where I'm not getting any intellisense in my IDE (Webstorm) when ...

TS2590: The resulting expression creates a union type that is too intricate to depict - VIM

I have incorporated typescript-vim into my workflow using code from the typescript-vim repository To make sure I have access to TypeScript functionalities, I globally installed typescript with the command npm install -g typescript In my project's pa ...