When reducing an Array of object keys, TypeScript automatically deduces the 'never' type in the accumulator object

const getObjectKeys = Object.keys as <T extends object>(obj: T) => Array<keyof T>;

interface AB {
    a: string;
    b: number;
}
export function testFunction(config: AB) {
    Utils.getObjectKeys(config).reduce((memo, key) => {
        **memo[key]** = config[key];
        return memo;
    }, {} as AB);
}

When encountering the error "TS2322: Type 'string | number' is not assignable to type 'never'. Type 'string' is not assignable to type 'never'," I resolved it by rewriting (memo as any)[key]. It seems this issue arises due to TypeScript's strong typing. To avoid this problem, one solution is to initialize the accumulator, memo, properly at the beginning.

Answer №1

Unfortunately, the compiler struggles to interpret the logic behind the line memo[key] = config[key] when key is a union type such as keyof AB. It fails to analyze the line based on the identities of the variables; instead, it solely focuses on their types. However, the validity of memo[key] = config[key] can be assured because the same key is used on both sides. If we introduced key1 and key2, both as type keyof AB, then the compiler's analysis would make more sense.

This level of analysis has been implemented in microsoft/TypeScript#30769. By executing memo[key1] = config[key2], the compiler recognizes that accessing config[key2] where key2 is a union results in another union, string | number. Yet, assigning to memo[key1] could potentially be unsafe. The only scenario for this assignment to be safe is if config[key2] could be assigned to

memo[key1]</code regardless of the specific value of <code>key1
. This implies that config[key2] must simultaneously be a string and a number: essentially an intersection of string & number. However, since there is no valid value for such a type, the compiler reduces this intersection to the impossible never type. Therefore, the compiler correctly marks memo[key1] = config[key2] as an error due to uncertainty about the specific value of
key1</code for a secure assignment. These analytical measures are valuable in detecting genuine errors.</p>
<p>With just <code>key
existing rather than key1 and key2, the compiler errs on the side of caution considering the unlikely event of assigning a string to a number or vice versa.


So, what is the solution? According to a comment from the developer of ms/TS#30769, ensuring TypeScript adheres to the intended logic involves defining the type of key as a generic type K constrained to a union instead of being a union itself. Essentially, you can make the reduce() callback generic as demonstrated below:

function test(config: AB) {
    getObjectKeys(config).reduce(<K extends keyof AB>(memo: AB, key: K) => {
        memo[key] = config[key];
        return memo;
    }, {} as AB);
}

This method works because both sides of the assignment are perceived as the generic type AB[K]. Interestingly, this approach poses similar risks to using a union (e.g., assigning key1 and key2 of type K, with K representing the full union keyof AB).indexed access types.

Playground link to 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

Potential issue with Jhipster: loading of data could be experiencing delays

I've encountered an issue with getting my chart to display properly. I am working on creating a chart using ng2-charts, where I retrieve data from a service and then display it on the chart. The problem arises when the data is not correctly displayed ...

Solving the Angular 11 issue of undefined array mapping

When using an API to retrieve a response array, I encountered an issue trying to map the "id" under the "quiz_records" array as it kept returning undefined. Despite believing that my code was correct, I couldn't figure out the problem. Here is the sn ...

Declare the type of variable associated with the store configuration

After setting up a pinia store using the setup store syntax as described in the documentation at , I encountered an issue while working with typescript and setup stores instead of option stores for my project. The problem arises with type annotations for ...

Angular index.html file can include a conditional script

I am currently working on an Angular project, where the index.html serves as the main entry point for the application, just like in any other Angular project. This file contains important links and configurations. Within the HTML code snippet below, you w ...

Resize the textarea to fit a maximum of five lines, and display a scrollbar if necessary

Explanation: I am facing an issue in Angular 2 regarding the chat screen. I need the chat screen to dynamically increase in size as I type, up to a maximum of 5 lines, and then show a scrollbar. How can I achieve this functionality? Problem: The current b ...

How to add unique elements to an array in Angular without any duplicates

I need help with pushing elements into an array and decrementing the count of it without duplicates in angular. Any assistance would be greatly appreciated ...

Ways to update HTML values using Events

I am attempting to retrieve a value using Events (ionic) once it listens for my 'onSMSArrive' event. I am able to successfully retrieve the value from the events. However, I am encountering an issue where the value is not updating in my app. Bel ...

Components in Angular that are conditionally rendered from a shared source

As someone who primarily specializes in backend development rather than Angular, I find myself facing a challenge and seeking guidance. Despite my lack of expertise with Angular, I am attempting to work out a concept that may or may not be feasible. My str ...

Is it more efficient to have deps.ts per workspace or shared among workspaces?

Currently, I am in the process of setting up my very first monorepo for a Deno-based application. In this monorepo, the workspaces will be referred to as "modules" that the API code can import from, with each module having its own test suite, among other t ...

Ways to retrieve a variable from a separate TypeScript document

A scenario arises where a TypeScript script contains a variable called enlightenFilters$: import { Component, Input, OnInit } from "@angular/core"; import { ConfigType, LisaConfig } from "app/enrichment/models/lisa/configuration.model"; ...

Ensuring the visibility of a child entity post soft deleting its parent entity in TypeORM

Here are the entities I am working with: class Parent extends BaseEntity{ @Column() name:string @OneToMany( ()=>Child, (Child)=>Child.Parent ) Child:Child[] @DeleteDateColumn() ...

The installation of @types/jquery leads to an unnecessary global declaration of $

In my package.json file, I have the following dependencies defined: { "dependencies": { "@types/jquery": "^3.5.5", } } This adds type declarations through @types/jquery/misc.d.ts, including: declare const jQuery: JQue ...

What is the best way to maintain the order of variadic types for conditionally inferred conditional types?

Here is the type definition that I am working with: type Inner<Type> = Type extends Wrapper<infer U>[] ? U[] : never; Additionally, I have a function with the following signature: function myFunc<From extends Wrapper[], To>( values: ...

What is the best way to define the type of an object when the Key is already known?

If I have the code snippet below, how can I properly define the data object type based on the known value of data.type? In this scenario, I aim to assign a specific type to data when its type property is either "sms" or "email" const payload = '{&quo ...

Navigating to the next page on a dynamic component in Angular 5 by

I'm uncertain if this scenario is feasible, but I have a page that fetches a list of items from an external API. There are currently 5 elements on the page, each acting as a link to its individual dynamically generated page through query strings. For ...

Function that sets object properties based on specified keys and verifies the value

Let's consider a scenario where we have an object structured like this: interface Test{ a: number; b: string; c: boolean; } const obj:Test = { a: 1, b: '1', c: true, } We aim to create a function that can modify the value ...

Specific TypeScript function that exclusively accepts types such as `number|undefined` and does not simply accept `number` alone

I've been working on creating a utility class that can help me throw an exception when something may be undefined, like throwIfUndefined(array[index]).function() and throwIfUndefined(obj.key).function(). My goal is to streamline my code as using if co ...

Can you explain the distinction, if one exists, between a field value and a property within the context of TypeScript and Angular?

For this example, I am exploring two scenarios of a service that exposes an observable named test$. One case utilizes a getter to access the observable, while the other makes it available as a public field. Do these approaches have any practical distincti ...

Unit test for PrimeNg Multiselect is not passing

While conducting unit tests for my component that includes various primeng components, I encountered an issue with the multi select component. All unit test cases are passing successfully except for the multi select which is returning the error message bel ...

Modify the content of a separate division by selecting a different item in a list with the help of Vue.js and TypeScript

I am still learning Vue and may not have all the answers. Currently, I am working on a feature that changes the text of another div based on the item I select from a list. You can find the code sandbox link below along with my current implementation. Code ...