Potential keys + keys that are present in the `initialData`

Is there a way to specify the type of data in order to include all keys that exist in initialData plus additional keys from Item as Partial(optional)?

class TrackedInstance<Item extends Record<string, any>, InitialData extends Partial<Item> = Partial<Item>>> {
  private _data: Partial<Item> = {}

  constructor(initialData: InitialData, isNew?: boolean) {
    this._data = initialData
  }

  get data() {
    return this._data
  }
}

interface User {
  name: string
  age: number
  isAdmin: boolean
}

const userInstance = new TrackedInstance<User>({
  name: ''
})

const test1: string = userInstance.data.name // Should be ok
const test2: number = userInstance.data.age // Should throw an error because age can be 'undefined' or 'number'

Ts playground

I believe it should look something like get data(): Pick & Partial> {

However, it gives an error:

TS2344: Type 'keyof InitialData' does not satisfy the constraint 'keyof Item'.

Answer №1

It is uncertain whether achieving this without using multiple functions is feasible.

An issue with TypeScript generics is that when one generic is specified, all others must also be specified. With generics that have default values, specifying one parameter will automatically set the others to their default value. Hence, TrackedInstance<User> enforces it to be

TrackedInstance<User, Partial<User>>
.

User jcalz raised this concern in the comments regarding interference of generic parameters for non-specified ones.

As mentioned, achieving this might require utilizing multiple functions to work around the "default generic value" issue, as shown by the solution involving multiple function calls:

class TrackedInstance<Item extends Record<string, any>, InitialData extends Partial<Item> = Partial<Item>> {
    private _data: InitialData;

    constructor(initialData: InitialData, isNew?: boolean) {
        this._data = initialData
    }

    get data(): InitialData {
        return this._data
    }
}

interface User {
    name: string
    age: number
    isAdmin: boolean
}

function track<T>() {
    return function <D extends Partial<T>>(initialData: D, isNew?: boolean) {
        return new TrackedInstance<T, D>(initialData, isNew);
    };
}

const userInstance = track<User>()({
    name: ''
})

const test1: string = userInstance.data.name // Should ok
const test2: number = userInstance.data.age // Should error because age can be 'undefined' | 'number'

Note that I had to adjust the type of your _data to be InitialData instead of just Partial<Item>. The code above results in the intellisense/error displayed below:

https://i.stack.imgur.com/Bg0Pn.png

In this case, .data only represents InitialData. If you also want "partial access" to the rest of the data, modify the type of your private _data field to be

InitialData & Partial<Item>
.

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

An issue has occurred: The function _co.deleteConsulta is not recognized as a valid function

While following a tutorial on creating a CRUD application using Firestore, I encountered an issue when trying to delete data from Firestore. Every time I attempt to delete a user from my Firestore database, I receive an error stating that ._co.deleteConsul ...

The presence of a constructor in a component disrupts the connection between React and Redux in

I am facing an issue with the connect function from 'react-redux' in my Typescript class example. The error occurs at the last line and I'm struggling to understand why it's happening. The constructor is necessary for other parts of the ...

What is the approach to constructing an observable that triggers numerous observables depending on the preceding outcome?

One of my endpoints returns { ids: [1, 2, 3, 45] }, while the other endpoint provides values for a given id like { id: 3, value: 30, active: true }. I am currently attempting to create an observable that will call the first endpoint and then, for each id r ...

Karma Test Requirement: make sure to incorporate either "BrowserAnimationsModule" or "NoopAnimationsModule" when using the synthetic property @transitionMessages within your application

TEST FILE import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { BrowserAnimationsModule } from '@angular/platform- browser/animations'; import { ManagePageComponent } from './manage-page.component& ...

Adjusting Image Sizes in React using Material-UI: A Guide to Automatically Resizing Images for Various Screen Dimensions

Having trouble making images within my React project responsive across different screen sizes. Using Material-UI, I currently set the maxWidth property with a percentage value which doesn't give me the desired outcome. Seeking advice on a more dynamic ...

Is there a way to automatically populate the result input field with the dynamic calculation results from a dynamic calculator in Angular6?

My current challenge involves creating dynamic calculators with customizable fields. For example, I can generate a "Percentage Calculator" with specific input fields or a "Compound Interest" Calculator with different input requirements and formulas. Succes ...

The Cordova InAppBrowser plugin has not been properly set up

After running cordova plugin list, I noticed that the InAppBrowser plugin is listed. However, when I try to run my code on an android device, I receive this message in the console via Chrome Remote Debugger: Native: InAppBrowser is not installed or you ar ...

Update the form field with today's date in a JHipster application

In our current project in JHipster, we are facing a challenge with setting the default value of a form field as the current date. JHipster offers a moment format for dates, which is essentially an ngbdatepicker. However, when attempting to change the inpu ...

When attempting to pass props to children, Typescript triggers an error message

I am facing an issue with a component that renders a child based on the specific "league" a user is viewing, such as MLB. Typescript is throwing an error because I am not passing the correct props to the child component. However, the parent component has t ...

Transfer dynamically generated table data to the following page

Seeking guidance on a common issue I'm facing. I am creating a table using data from Firebase upon page load, and I want users to click on a row to view specific details of that item. It may sound confusing, but it will make more sense with the code p ...

Parent component interacting with child component

In my application, I have a header component along with registration and login components. The selector of the header component is used in both the login and registration components. There is also a button in the header that displays as a login button if t ...

The addition operator is not compatible with the given types

Hello, I am currently working on integrating PayPal into an Angular 5 project. The code snippet below shows how I render PayPal buttons using a function: ngAfterViewChecked(): void { if (!this.addScript) { this.addPaypalScript().then(() => { ...

ERROR: The variable countryCallingCode has not been defined

I encountered an error when attempting to assign a value to my property countryCallingCode, which does not exist in the first option. this.allData.customerFacingPhone.countryCallingCode = newItem.countryCallingCode The error message I received was: ERROR ...

transformation of categorized unions in software development

Experimenting with routing-controllers and its built-in class-transformer feature, I tried creating an interface for executing a search query based on either a location id or location coordinate. My aim was to utilize a discriminated union as a body parame ...

Choose does not showcase the updated value

My form contains a form control for currency selection Each currency object has the properties {id: string; symbol: string}; Upon initialization, the currency select component loops through an array of currencies; After meeting a specific condition, I need ...

The number of keys in the related object must correspond to the length of the array in Advanced Generic Types

Can we achieve type safety across rows and columns by having one object define the structure of another? Starting Point: export interface TableColumn { name: string; type: "string" | "number" | "action"; id: string; } ...

Creating a TypeScript function that can dynamically assign values to a range of cells within a column, such as AD1, AD2, AD3, and so on

Hello there I'm currently working on a function that will dynamically assign values to the column range of AE to "AD" + i. However, when I use the function provided below, it only writes AD5 into the first 5 columns instead of AD1, AD2, AD3, and so o ...

Angular Delight: Jaw-Dropping Animation

After setting up my first Angular project, I wanted to incorporate Angular Animations to bring life to my content as the user scrolls through the page. I aimed to not only have the content appear on scroll but also implement a staggering animation effect. ...

Error TS2307: Module 'calculator' could not be located

Running a Sharepoint Framework project in Visual Studio Code: This is the project structure: https://i.stack.imgur.com/GAlsX.png The files are organized as follows: ComplexCalculator.ts export class ComplexCalculator { public sqr(v1: number): number ...

What is the best way to hand off this object to the concatMap mapping function?

I'm currently in the process of developing a custom Angular2 module specifically designed for caching images. Within this module, I am utilizing a provider service that returns Observables of loaded resources - either synchronously if they are already ...