Securely transfer data between objects using a for loop

Description

I have two similar types that are not identical:

type A = {
  a?: number
  b?: string
  c?: boolean
}

type B = {
  a?: number
  b?: string
  c?: string
}

I am looking to create an adapter function f() that can convert type A to type B, with the condition that only properties populated in A should populate B.

function f(a: A): B 

One possible approach is using a for loop:

function f(a: A): B {
  const b: B = {}
  for (const key of Object.keys(a) as Array<keyof A>) {
    if (key === 'c') {
      b.c = String(a[key])
    } else {
      b[key] = a[key] // ❌ Type 'string | number | undefined' is not assignable to type 'undefined'.
    }
  }
  return b
}

The above code seems to be working and logically type safe. TypeScript might not fully grasp its type safety, prompting further exploration on how to make it better understand the types involved.


What I've tried

  1. Conditional branching based on value type:
function g(a: A): B {
  const b: B = {}
  for (const key of Object.keys(a) as Array<keyof A>) {
    if (key === 'c') {
      b.c = String(a[key])
    } else if (key === 'a') {
      // Handle numbers
      b[key] = a[key]
    } else {
      // Handle strings
      b[key] = a[key]
    }
  }
  return b
}

However, this approach leads to duplicate code in multiple branches and could violate the open-closed principle when updating keys or values.

  1. Using object spreading:

While efficient, concerns arise about creating multiple objects just to spread them into another. Surely there must be a simpler and more streamlined solution to achieve the desired outcome?

Answer №1

It is important to note that TSC does not recognize any remaining keys as guaranteed to have the same value. There is no direct correlation between the remaining properties of A and B once C has been removed.

Therefore, you have two options: either explicitly construct the new object B by specifying its properties, or establish a type hierarchy so that they inherit from each other.

Instead of using an imperative iterator, focus on helping TSC separate the shared properties and explicitly extracting them.

explicit approach:

type A = {
  a?: number;
  b?: string;
  c?: boolean
}

type B = {
  a?: number;
  b?: string;
  c?: string
}

function f(a: A): B {
  const b: B = {
      a: a.a,
      b: a.b,
      c: String(a.c),
  };

  return b;
}

inheritance:

type SharedProps = {
    a?: number;
    b?: string;
}

type A = SharedProps & {
  c?: boolean
}

type B = SharedProps & {
  c?: string
}

function f(a: A): B {
  const { c: aC, ...shared } = a;

  const b: B = {
      c: String(aC),
      ...shared
  };

  return b;
}

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

Angular: Utilizing the new HttpClient to map HTTP responses

Within my application, I have a standard API service that communicates with the backend using requests structured like this: post<T>(url: string, jsonObject: object): Observable<T> { return this.http.post<T>(url, JSON.stringify(json ...

Issues with TypeScript arise when transferring arguments between functions

Encountering a TypeScript error due to this pattern: Error message: 'Argument of type '(string | number)[]' is not assignable to parameter of type 'string[] | number[]' function foo(value: string | number) { return bar([va ...

Tips for capturing an error generated by a child component's setter?

I've created an App component that contains a value passed to a Child component using the @Input decorator. app.component.html <app-child [myVariable]="myVariable"></app-child> app.component.ts @Component(...) export class AppC ...

Encountering a Vueify Typescript error in a Vue project

Recently diving into the world of Vue, I was able to successfully create a sample app using gulp, vueify, and TypeScript. To showcase what's happening and shed light on an issue I'm facing, here are snippets of the key code segments: Menu.ts im ...

Struggle with Transmitting Information in Ionic 2

I have been working on an Ionic project that involves a JSON file with preloaded data. The initial page displays a list from which a user can select an item to view its content. However, I am encountering a "Response with status: 404 Not Found for URL" err ...

The language in the React Native app remains unchanged despite utilizing i18next.changeLanguage

I am currently attempting to integrate the i18next library into my React Native app in order to facilitate language changes, but I have encountered difficulties with translation. image description here I have created an i18n.tsx file. import i18next from & ...

Experiencing a lengthy installation process of TypeScript on Node.js

I attempted to set up TypeScript on my laptop running MS Windows 8.1 (64-bit). After installing Node.js 64-bit, I ran the command npm install -g typescript. However, the installation appeared to stall with a spinning '/' for over 2 hours. When I ...

Transferring data between unrelated components

I am facing an issue where I am unable to pass a value from the Tabs component to the Task component. To address this, I have created a separate data service. The value in the Tabs component is obtained as a parameter from another component. However, when ...

Tips for building an effective delete function in Angular for eliminating a single record from a table

I've been working on creating a method to delete an employee by their ID, and I've tried various approaches in my VS Code. Unfortunately, all of them have resulted in errors except for this specific method. Whenever I click on the delete button, ...

Troubles with Typescript typings when including an empty object in an array with specific typings

, I am facing a dilemma with displaying houses in a cart. Each house has an image, but since they load asynchronously, I need to show empty cards until the data is fetched. Initially, I added empty objects to the array representing the houses, which worked ...

Assign a specific value to each object

Receiving data from the backend in a straightforward manner: this.archiveService.getRooms(team).subscribe( res => { this.form = res; this.form.forEach(el => { el.reservation.slice(-6).match(/.{1,2}/g).join('/'); }); }, ...

Mastering Inter-Composable Communication in Vue 3: A Guide

Composables in Vue documentation demonstrate how small composition functions can be used for organizing code by composing the app. Discover More About Extracting Composables for Code Organization "Extracted composables act as component-scoped servi ...

Discovering the type in Typescript by specifying a function parameter to an Interface

Consider this sample interface: interface MyInterface { x: AnotherThing; y: AnotherThingElse; } Suppose we make the following call: const obj: MyInterface = { x: {...}, y: {...}, } const fetchValue = (property: keyof MyInterface) => { ...

AngularFire 2 dispatching email for password reset

I am looking to add a feature for resetting passwords or handling forgotten passwords using AngularFire2. It looks like the function sendPasswordResetEmail is either not available in AngularFire2 or the typings have not been updated yet. I tried accessing ...

How to add an item to an array in JavaScript without specifying a key

Is there a way to push an object into a JavaScript array without adding extra keys like 0, 1, 2, etc.? Currently, when I push my object into the array, it automatically adds these numeric keys. Below is the code snippet that I have tried: let newArr = []; ...

Issue with index creation using the @index decorator in Typegoose with NestJS and MongoDB

Encountering an issue with typegoose. Trying to create a 2dsphere index on the property geoLocation of model SP. Utilized the typegoose decorator @index but it's not functioning and not throwing any errors. Uncertain about how typegoose handles this s ...

Problem encountered while initializing a new project using Angular-CLI version 6.1.2

After attempting to create a new Angular project using ng new angular-6-boilerplate, I encountered an issue with the latest version of angular-cli. Despite using the terminal for Windows to set up my project, an error occurred: The input for the schemat ...

Achieving a delayed refetch in React-Query following a POST请求

Two requests, POST and GET, need to work together. The POST request creates data, and once that data is created, the GET request fetches it to display somewhere. The component imports these hooks: const { mutate: postTrigger } = usePostTrigger(); cons ...

Create a Typescript generic function that can return a variety of data types including strings, numbers, and

I have a function written in Typescript and I am looking to determine the return type based on the value retrieved from process.env. For instance, the variables in my Node process.env can be strings, numbers, or booleans. I want to fetch them with their s ...

Encountering Problem **Issue: Invalid hook call. Hooks are intended to be used only within the body of a function component. **

i am facing an issue with Material UI in my ReactJS app. Without the below code (Component), my app works fine, but when I try to use it, I encounter an error: Error: Invalid hook call. Hooks can only be called inside of the body of a function component.. ...