Error encountered when attempting to assign a value of the original data type within the Array.reduce function

I am in the process of developing a function that takes a boolean indicator object like this:

const fruits = {
  apple: false,
  banana: false,
  orange: false,
  mango: false,
};

Along with an array such as ['apple', 'orange']. The goal is to return an object similar to the input object structure, with properties from the array set to true.

I have written these TypeScript functions to accomplish this task


// Helper function for typing Object.Keys
const objectKeysTyped = <Obj extends object>(obj: Obj) => {
  return Object.keys(obj) as (keyof Obj)[];
};

// Main function
const arrayToBoolIndicator = <Obj extends Record<string, boolean>>(
  boolFramework: Obj,
  arrayOfIncluded: (keyof Obj)[]
) => {
  return objectKeysTyped(boolFramework).reduce(
    (acc, cur) => {

      // TS Error on the next line: Type 'boolean' is not assignable to type 'Obj[keyof Obj]'.
      acc[cur] = arrayOfIncluded.includes(cur); 

      return acc;
    },
    { ...boolFramework }
  );
};

Typescript Playground link

Can anyone explain why I am encountering a TypeScript error when trying to assign the original type to the property of an object?

Answer â„–1

The compiler raises a concern regarding the assignment of boolean to the properties of Obj; only the reverse assignment is guaranteed. This issue arises due to the existence of true and false literal types, which are more precise than boolean. If a property has a type of true, assigning a generic boolean value may lead to compatibility issues since it can be false. Similarly, if the property type is false, assigning any boolean value might result in a mismatch with actual values. Therefore, assigning a boolean value to acc[cur] triggers a warning from the compiler.

Consider this example:

const x = { a: true, b: false } as const;
/* const x: { readonly a: true; readonly b: false; } */

const y = arrayToBoolIndicator(x, ["b"]);
// const y: { readonly a: true; readonly b: false; }
console.log(y);  // {a: false, b: true}, indicating an issue
(y.a && "abc").toUpperCase(); // compiles successfully but throws a runtime error!

In this scenario, x is initialized with constant assertions for its properties: a being true and b being false. However, when calling arrayToBoolIndicator(x, ["b"]), the expected output doesn't align with the actual implementation—resulting in the a property of y becoming false during runtime. Consequently, the compiler permits (y.a && "abc").toUpperCase() as if y.a were still

true</code, potentially leading to issues at runtime.</p>
<p>The compiler error stemming from <code>arrayToBoolIndicator()
serves as a cautionary flag for such complications. While this might not pose a real-life problem frequently, it underpins the current issue.


To address this situation, simply specify that the accumulator's property types are exclusively boolean, distinct from Obj's property types:

const arrayToBoolIndicator = <Obj extends Record<string, boolean>>(
  boolData: Obj,
  includedKeys: (keyof Obj)[]
) => {
  return objectKeysTyped(boolData).reduce<Record<keyof Obj, boolean>>(
    //              specify type argument --> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    (acc, cur) => {
      acc[cur] = includedKeys.includes(cur);
      return acc;
    },
    { ...boolData }
  );
};

This approach manually specifies the type argument within the reduce() method as Record<keyof Obj, boolean>, ensuring acc[cur] anticipates a boolean.

By doing so, you eliminate the previous risk:

const x = { a: true, b: false } as const;
/* const x: { readonly a: true; readonly b: false; } */

const y = arrayToBoolIndicator(x, ["b"]);
// const y: const y: Record<"b" | "a", boolean>

(y.a && "abc").toUpperCase(); // now prompts a compiler error!
// ----------> ~~~~~~~~~~~
// Property 'toUpperCase' does not exist on type 'false | "abc".

With this adjustment, although the properties of x retain boolean literals, the output of the function y possesses a type of {a: boolean, b: boolean}, making y.a && "abc" no longer assumed to be strictly a string. The compiler rightfully flags the call to a potential non-existent toUpperCase() method.

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

The compatibility between Typescript methods and event handlers is lacking

Consider this basic TypeScript script class foo { v: number = 1; public bar() { console.log(this.v); } } var a = new foo(); var b = new foo(); document.getElementById('test').addEventListener("click", a.bar); document.getE ...

The alias for the last item in a nested ng-repeat loop will consistently evaluate to true

Within my code, I am utilizing two nested ng-repeat functions and I am looking to change the $last variable to something different for each level - let's say outerLast and innerLast. I attempted to achieve this by using ng-init="outerLast= $last" and ...

Could there be any issues with the structure of my mongoose schema?

I've been stuck for 3 hours trying to solve this problem. I can't seem to retrieve any data from my document. var mongoose = require('mongoose'); var Schema = mongoose.Schema; var accountSchema = mongoose.Schema({ username: String ...

The production build encountered an issue as it was anticipating 3 arguments, however, it only received

import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'elipsis' }) export class ElipsisPipe implements PipeTransform { transform(text, length, clamp) { text = text || ''; clamp = clamp || '...& ...

Repetitive use of multiple submit buttons in AngularJS

i'm currently working with AngularJS Currently facing this issue: view screenshot I have utilized the following HTML code to display submit button for two different types of forms. One for TEXT Form and one for ENUM Form: <div ng-controller="g ...

Click to delete the <p> element

For the past few days, I've been struggling with this issue and have tried various approaches to solve it. However, I can't seem to remove the element for some reason. Can anyone offer some insight? My objective is to add the inputted markup on ...

Efficiently scheduling file downloads using WebDriver automation

I am in the process of automating a website using WebDriver, but I have encountered unique file download requirements that differ from what is readily available online. My specific scenario involves a website where I create orders. Upon clicking the &apos ...

Using JavaScript, concatenate text from each line using a specified delimiter, then add this new text to an unordered list element

I am looking to extract text from named spans in an unordered list, combine them with a '|' separating each word within the same line, and append them to another ul. Although my code successfully joins all the words together, I'm struggling ...

Observing Gulp's behavior is quite peculiar - it seems to be running

I ran into a rather peculiar issue with gulp watch. In my system, I have two disk drives: D and E. Disk D is a section of my computer's hard disk drive, while disk E is a flash drive. Both disks contain a file named test.txt: D:\test\test ...

Material-UI: The call stack has exceeded the maximum range, causing an Uncaught RangeError

I am currently utilizing the Dialog and Select components offered by Material-UI in conjunction with React. Here is a quick example: import React from 'react'; import { Dialog, MenuItem, Select } from '@material-ui/core'; class Examp ...

Using CSS to position elements absolutely while also adjusting the width of the div

In one section of my website, I have a specific div structure. This structure consists of two divs stacked on top of each other. The first div is divided into two parts: one part with a width of 63% and another part with a button. Beneath the first div, t ...

Having issues with referencing external JavaScript and CSS files in Angular 6

Dealing with an angular6 project and a bootstrap admin dashboard template, I'm facing issues importing the external js references into my Angular application. Looking for guidance on how to properly import and refer to external Js/CSS files in an angu ...

The strict-origin-when-cross-origin policy is enforced when submitting a POST request through a form to a specific route

Currently, I am diving into the world of Node.js, express, and MongoDB by reading Greg Lims's book. However, I've hit a roadblock when trying to utilize a form to submit data to a route that should then output the body.title of the form in the co ...

Is it possible to combine Django urls and Vue routes in a single project?

After setting up my Django app and implementing the authentication layer using Django-Allauth with features like email confirmation, password reset, and two-factor authentication, I've come to the realization that for my app's interactive nature ...

Angular 8: Implementing Form Validation with a Boolean Flag

Within my HTML code, I have a function (change)="limitUser($event)". In Typescript, I utilize a for loop to iterate through each element and determine if the value is less than 10. If it exceeds 10, the inValid = true condition is set. All form fields in m ...

Shattered raw emotion

Does anyone have any insight on how to resolve this error? I've hit a roadblock trying to figure out the issue in the message below. Here is the snippet of code: :label="` ${$t('cadastros.clientes.edit.status')}: ${cliente.status === ...

The Vercel/NextJS deployment does not delay the completion of the serverless function until the email is sent via Azure

Upon a user's registration, I am attempting to send a registration/account activation email. While the email sends successfully via Azure's email services when running on localhost, deployments on Vercel do not trigger the email (although the use ...

canvasJS: unable to load the chart

This is my first time using canvajs, but unfortunately, it's not working as expected. Can someone please review my code? data.php <?php header('Content-Type: application/json'); include './traitement.php'; $data =array(); ...

Using jQuery to extract the value of an object from an <li> element and updating the class attribute of the <li> element

There is a div element: <div id="ddDistr" class="searchBoxSortDistrict" tabindex="1"> <ul id="ddd"> </ul> </div> I have inserted HTML from json into it: $("#ddd").html(" "), $.each(dis, function( index, value) { $("#dd ...

Save the HTML elements in an object and then use the ng-include directive to include the template

Currently experimenting with this code snippet: var CustomTable = function($elem) { this.properties.element = $elem; this.initialize(); }; CustomTable.prototype.PROPERTIE = { secondElement: $('.second') // this element ...