Dynamic assignment of values to an object literal in Typescript

I've been troubleshooting this issue for hours and I'm stumped by this specific typescript error.

Although I can't share the actual code, I've simplified the problem to the example below:

    abstract class CustomerType {
        protected abstract customerInfo?: IUserInfo;
    }
    
    enum CustomerGroup {
        FirstTimer = "first timer",
        Subscriber = "subscriber"
    }
    
    interface IUserInfo {
        group?: CustomerGroup;
        firstClassMember?: boolean;
        rewardsMember?: boolean;
    }
    
    abstract class CustomerType {
        protected abstract customerInfo?: IUserInfo;
    }
    
    class Default extends CustomerType {
        protected customerInfo: IUserInfo = {};
        constructor(){
            super();
        }
        
        get _customerInfo{
            return this.customerInfo ?? {}
        }
        
        set _customerInfo(customerInput: IUserInfo){
            let input: keyof IUserInfo;
            for(input in customerInput){
                if(customerInput[input] === undefined) continue;
                    this.customerInfo = customerInput[input];
            }
        }
    }

The Typescript error encountered is as follows:

Type 'boolean | CustomerGroup | undefined' is not assignable to type 'IUserInfo'. Type 'undefined' is not assignable to type 'IUserInfo'.(2322)

Despite the validation just above, Typescript fails to detect that customerInput[input] is definitely not undefined.

Check out the Typescript playground link here: TS Playground Link

Take a look at the codepen with the issue: CodePen Link

Answer №1

The correct code to use is as follows:

set _customerInfo(customerInput: IUserInfo){
    let input: keyof IUserInfo;
    for(input in customerInput){
        if(customerInput[input] === undefined) continue;
        this.customerInfo[input] = customerInput[input];
    }
}

Initially, it's unclear why TypeScript is flagging an error upon first look.

An alternative and more concise way to write the same function would be:

set _customerInfo(customerInput: IUserInfo){
    Object.assign(this.customerInfo, customerInput)
}

The loop in your original code was incorrect because you were replacing the entire this.customerInfo, which should consist of multiple values, with a single value. This led to your error.

A helpful tip is to run the code and analyze the output whenever unsure about TypeScript errors. Writing tests simultaneously with coding can also prevent such issues from occurring.

For instance, running the following test could have revealed the issue:

const a = new Default();

a._customerInfo = { rewardsMember: true };

t.deepEqual(a._customerInfo, { rewardsMember: true })

If executed, the test runner would have indicated that a._customerInfo is true rather than { rewardsMember: true }.

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

Utilizing files that do not have the extension '.ts' or '.tsx' within the 'ts_library' as dependencies

My current challenge involves importing a JSON file from TypeScript while utilizing the resolveJsonModule flag in my tsconfig. The problem lies in how I can provide this JSON file to ts_library since it seems unable to locate the file. This issue extends t ...

Utilize @types for the Typescript npm library without the need for downstream projects to install this dependency

Our npm library package, built in TypeScript and known as lib-utils, provides a range of utilities for other projects to leverage. One of the dependencies within lib-utils is d3, which is both a peerDependency and a devDependency. Additionally, there is a ...

gcc compiler outputting errors due to unrecognizable references

Recently, I encountered an issue with my code that is designed to read text from a file and perform some computations. The error message I received while trying to compile the code (file name: pp3.c) is as follows: /tmp/ccnZaQld.o:pp3.c:(.text+0x5f): unde ...

Creating XML templates in Angular 7: A comprehensive guide

How do I pass XML values in Angular 7 when the API requires this specific format of XML code? -modifydata "<datasets><dataset select=\""always\""> <replace match=\""Letter/@FName\"" value=\""Nazeeeeeeeeeeeeer\" ...

Experimenting with async generator using Jest

It has become clear that I am struggling with the functionality of this code, especially when it comes to testing with Jest. Despite my efforts to use an await...of loop, I am not getting any output. The file path provided to the generator is correct and I ...

Issue encountered during project upload due to deployment error

Make sure to wrap useSearchParams() in a suspense boundary on the "/auth-callback" page. For more information, check out https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout import React, { useEffect } from 'react'; import { useRou ...

I'm having trouble setting a value for an object with a generic type

I am attempting to set a value for the property of an object with generic typing passed into a function. The structure of the object is not known beforehand, and the function receives the property name dynamically as a string argument. TypeScript is genera ...

A tutorial on ensuring Angular loads data prior to attempting to load a module

Just starting my Angular journey... Here's some code snippet: ngOnInit(): void { this.getProduct(); } getProduct(): void { const id = +this.route.snapshot.paramMap.get('id'); this.product = this.products.getProduct(id); ...

Converting data received from the server into a typescript type within an Angular Service

Received an array of Event type from the server. public int Id { get; set; } public string Name { get; set; } public DateTime Start { get; set; } public DateTime End { get; set; } For Angular and TypeScript, I need to transform it into the following clas ...

The lib.dom.d.ts file is seriously lacking in many key components

Are there any updated versions of lib.dom.d.ts? The current one is missing a lot of essential information, causing numerous compilation errors. For example, consider this line: window.File && window.FileReader && window.FileList && ...

Issues detected with the functionality of Angular HttpInterceptor in conjunction with forkJoin

I have a Service that retrieves a token using Observable and an HttpInterceptor to inject the token into every http request. It works seamlessly with a single request, but when using forkJoin, no response is received. Here is the code for the interceptor: ...

Broaden the attributes of an existing function

I am currently developing a Koa web server and I am exploring if it's feasible to include an additional parameter to an already established method on the Koa.app object. const mongoState = await connectToDatabase(); app.use(async (ctx, next) => ...

What is the best way to integrate a jQuery Plugin into an Angular 5 application powered by TypeScript 2.8.1

I am trying to incorporate jQuery into my Angular 5 project using TypeScript 2.8.1. I attempted to follow Ervin Llojku's solution but it didn't work: First, install jquery via npm npm install --save jquery Next, install the jquery types npm i ...

Simplified File Paths and Default Files

Currently, I am working with Next.js and TypeScript, setting up path aliases in my project without any issues. However, I'm facing a small difficulty when it comes to dealing with index.ts files within folders. My goal is to achieve something similar ...

After being awaited recursively, the resolved promise does not perform any actions

When working with the Twitter API, I need to make recursive method calls to retrieve tweets since each request only returns a maximum of 100 tweets. The process is straightforward: Call the function and await it Make an HTTP request and await that If the ...

Add a decorator to all functions in a TypeScript class to list all available methods

How can I apply a decorator function to all methods within a class in order to streamline the code like this: class User { @log delete() {} @log create() {} @log update() {} } and have it transformed into: @log class User { ...

The assigned type does not match the type 'IntrinsicAttributes & { children?: ReactNode; }'. This property is not assignable

I have been struggling to resolve this issue, but unfortunately, I have not found a successful solution yet. The error message I am encountering is: Type '{ mailData: mailSendProps; }' is causing an issue as it is not compatible with type &apos ...

Step-by-step guide on filtering an array of objects using Vuejs and TypeScript

For this particular project, I am utilizing Vuejs Typescript with a data structure that looks like this: ["order": { "id":1, "created_at":"2019-12-06T10:22:17Z", "status":"open", ...

Access a Map URL through a native mapping application on your device

Q: I'm looking to open a specific type of link on the Native Map app. Can anyone recommend a plugin that would work for this scenario? https://www.google.com/maps?q=15405 Hebbe Ln+Au... I tried using the Capacitor Browser plugin and it worked well o ...

Choosing from a list in Angular

I'm trying to make a dropdown menu that shows options in the format "code-description", but only displays the "code" portion when an option is selected. For example, showing "A-Apple" in the dropdown, but displaying only "A" when chosen. I am able to ...