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

Is it possible to use Ajax to prompt a pop-up window for basic authentication when logging in?

While attempting to access the reed.co.uk REST web API in order to retrieve all related jobs, I am encountering an issue. Despite passing my username and password, a popup window keeps appearing when I call the URL. The alert message displayed reads: i ...

How can I set the default bindLabel for a dropdown in @ng-select/ng-select when the self change event occurs in Angular

I have a scenario where I need to set the default value to null in the ng-select. If the user selects an option from the dropdown first, then on the change event it should check if the Amount model is not null or blank. If the Amount model is blank, then ...

Can the automatic casting feature of TypeScript be turned off when dealing with fields that have identical names?

Imagine you have a class defined as follows: Class Flower { public readonly color: string; public readonly type: string; constructor(color: string, type: string) { this.color = color; this.type = type; } Now, let's introduce anoth ...

The blank screen mystery: ionic and Google maps integration not playing nice

I've been struggling to integrate Google Maps into my web application. Unfortunately, all I see is a blank screen with no errors. Here's the current code snippet that I have. It seems like there might be an issue with the mapElement variable, but ...

How do I return a <div> element to its initial state after JavaScript has made changes to it?

So, I have this situation where a DIV contains a form. After users submit the form successfully, I want to replace the form with a simple message saying "everything is good now". This is how I currently do it: $("#some_div").html("Yeah all good mate!"); ...

Troubleshooting connectivity issues between Entities in microORM and Next.js

While trying to run my Next.js application in typescript, I encountered the following error: Error - ReferenceError: Cannot access 'Member' before initialization After consulting the documentation at https://mikro-orm.io/docs/relationships#relat ...

What is the reason behind HTML5Boilerplate and other frameworks opting for a CDN to host their jQuery files

When it comes to loading jQuery, HTML5Boilerplate and other sources[citation needed] have a standard process that many are familiar with: <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script>window. ...

Adjust the size of the mat-expansion indicator to your desired height and width

Trying to modify the width and height of the mat indicator has been a bit challenging. Despite following suggestions from other similar questions, such as adjusting the border width and padding, I am still unable to see the changes reflect in my CSS file ...

Utilizing NPM Package Configuration Variables with Docker Commands: A Guide

I have a unique file structure where my package.json contains a single variable called settings which defines the port for the application: package.json ... "settings":{ "port": "3000" }, ... In addition, I've set up a custom script to execute a ...

Is Immutable state considered a key functional aspect in the ReactJs framework?

One key aspect of an imperative program is the emphasis on state and its modifications. When it comes to ReactJs, there is a push for more functional programming styles, such as using purity and higher-order functions. I'm curious to explore whether ...

Synchronize chat messages automatically with the scrolling window using AJAX technology

Original Content Scrolling Overflowed DIVs with JavaScript In my AJAX chat application, messages are displayed in a div with overflow: auto, enabling the scroll bar when the content exceeds the space. I am looking for a solution that automatically scrol ...

Sending a reference to the event object within a JavaScript function

There are times when we need to use the event object in JavaScript. Below is an example of how we can pass the event: function test(e){ console.log(e); e.preventDefault(); console.log("You are not going to redirect"); } HTML <a href="www. ...

Within the Django framework, where should I place the Python script that needs to be called by a JavaScript function?

When it comes to Django and file locations, I often find myself getting confused a lot, especially since I am using Django 1.10. Currently, in my static/(django-proj-name)/js/ folder, I have my main.js file where I need to call a Python script along with t ...

Divide MUI theme into individual files

I have encountered an issue in my Next.js project. I currently have an index.ts file residing in the src/theme directory. 'use client'; // necessary for MUI to work with nextjs (SSR) import { createTheme } from '@mui/material/styles'; i ...

Capture the onclick attribute with jQuery and then reapply it

I am facing a challenge with a page that has several calendars composed of HTML tables where each day is represented by a td. The td elements have an onClick attribute which I need to manipulate using jQuery. Specifically, I need to remove the onClick attr ...

Unable to decrease the width of a div element in Vuetify and Nuxt

As I work on creating a dynamic form with fields that need to occupy only 50% of the size of a regular field, I encounter different components based on data provided by Vuex. The use of v-for in Vue.js helps me loop through form objects and render the app ...

Guide to setting up Firebase pagination in a NextJS 13 server component

Currently, I am working on developing a product page that showcases all products and functions as a server component. The challenge I am facing is the inability to pass the last visible document snapshot required by the startAfter() query. Below is the fu ...

The issue persists with the event listener not responding to input key

Can the Keycode that is pressed during the firing of addEventListener input be retrieved? <p contentEditable="true" id="newTask">New task</p> document.getElementById("newTask").addEventListener("input" ...

(Critical) Comparing AJAX GET Requests and HTTP GET Requests: identifying the true client

When a typical GET request is made through the browser, it can be said that the browser acts as the client. However, who exactly serves as the client in the case of a GET request via AJAX? Although it still occurs within the browser, I am intrigued to delv ...

Exploring ways to locate a specific text within a URL using nodeJS

Here is a simple code snippet with a problem to solve: var S = require('string'); function checkBlacklist(inputString) { var blacklist = ["facebook", "wikipedia", "search.ch", "local.ch"]; var found = false; for (var i = 0; i < b ...