How can I limit generic types to only be a specific subtype of another generic type?

Looking to create a data type that represents changes in an object.

For instance:

const test: SomeType = {
    a: 1,
    b: "foo"
};

const changing1: Changing<SomeType> = {
    obj: test,
    was: {
        a: test.a
    },
    now: {
        a: 3
    }   // Correct one

const changing2: Changing<SomeType> = {
    obj: test,
    was: {
        a: test.a
    },
    now: {
        b: "bar"
    }   // Incorrect one

Attempted to accomplish this with the following code:

type Changing<T, K = {[R in keyof T]: T[R]}, P extends K = {[R in keyof K]: K[R]}> = {
    obj: T,
    was: K,
    now: P
}

The initial idea was to constrain P as an extension of K but with the same members. It seems like it doesn't work as expected.

Answer №1

To systematically cover all possible options for each property, we can utilize a mapped type and then gather all options into a union. This approach ensures that the scenario you anticipate as an error will indeed be flagged as an error:

interface SomeType {
    a: number,
    b: string
}
const test: SomeType = {
    a: 1,
    b: "foo"
};

const changing1: Changing<SomeType> = {
    obj: test,
    was: {
        a: test.a
    },
    now: {
        a: 3
    } 
}

const changing2: Changing<SomeType> = { // error
    obj: test,
    was: {
        a: test.a
    },
    now: {
        b: "bar"
    }  
}

type Changing<T> = {
    [P in keyof T]: {
        obj: T,
        was: Pick<T, P>
        now: Pick<T, P>
    }
}[keyof T]

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

Troubleshooting issues with TypeScript D3 v4 module import functionality

As I embark on the journey of creating a miniature JS library using D3 to visualize line charts, I find myself navigating unfamiliar waters. However, I believe that deep diving into this project is the most effective way for me to learn. Below is the cont ...

The 'filter' property is not found on the type '{}'

I'm currently attempting to implement a custom filter for an autocomplete input text following the Angular Material guide. https://material.angular.io/components/autocomplete/overview Here's what I have so far: TS import { Component, OnInit } ...

Trying out Angular2 service using a fabricated backend

Just a heads up: I know Angular2 is still in alpha and undergoing frequent changes. I am currently working with Angular2 and facing an issue with testing an injectable service that has a dependency on http. I want to test this service using a mock backend ...

TS: Utilizing a generic parameter in an overloaded function call

This piece of code encapsulates the essence of what I'm trying to achieve more effectively than words: function A(a: string): string; function A(a: number): number; function A(a: any) { return a; } function B<T extends number | string>(arg: T): ...

Ways to Prompt a User to Select the "Remember Me" Option

How can I implement the functionality of 'Remember Me' on a login page? I want users who click on 'Remember Me' to be able to reopen the page without logging in again, even after closing their browser. But how do I differentiate between ...

Is there a way to ensure that only individual objects are selected in FabricJS on the Canvas, rather than a group of objects?

One issue I am facing is with my method for selecting objects on the canvas by clicking a button. How do I ensure that it skips selecting groups and only selects individual objects? Generating a group of shapes here: const group = new fabric.Group([ ...

Moment.js is stating that there is no property called 'toISOString' on the type '{}'

I'm facing an issue with my code - the `value.toISOString()` function was working fine until now, but suddenly it's throwing a compiler error. I recently upgraded from Angular 7 to 8, which also bumped up the Typescript version to 3.4.5. Any sugg ...

Display an API generated popup list using Vue's rendering capabilities

I'm attempting to generate a pop-up within a displayed list using custom content retrieved from an API request. Currently, my code looks like this: <template> <div class="biblio__all"> <a v-for="i in items" ...

When attempting to inject a provider from the same module, the dependencies cannot be resolved

Bug Report Current Issue Encountering an error when trying to instantiate the PaymentProcessorModule: Error: Nest cannot resolve dependencies of the PaymentProcessor (?, PaymentsService, ProcessingService). Please ensure that the TransactionsService argum ...

Struggling to establish object notation through parent-child relationships in Angular 2

Hi there, I am new to Angular and JavaScript. Currently, I am working on achieving a specific goal with some data. data = ['middlename.firstname.lastname','firstname.lastname']; During the process, I am looping through the .html usin ...

The export from chart.js does not include a member named 'ChartDataSets'. Perhaps you were referring to 'ChartDataset'? ts(2724)

Encountered an error message when trying to import ChartDataSets in line-chart.component.ts 'chart.js' does not have a member named 'ChartDataSets'. Perhaps you meant 'ChartDataset'? Uncertain about the source of the issue. C ...

What could be causing the cyclic dependency problem after upgrading to Angular 9?

I am experiencing an issue with a specific file containing the following code: import { Injectable } from '@angular/core'; import { I18n } from '@ngx-translate/i18n-polyfill'; import { isNumber } from 'lodash'; import { Confir ...

Steps to resolve the issue of 'type is not assignable to any' while working with a member

I'm facing an issue with a code snippet like the one below: interface IFoo { bar: string; baz: number; } function f(foo: IFoo, name: 'bar' | 'baz', val: any) { foo[name] = val; // <<< error: Type 'any' i ...

"What is the best way to calculate the total value of an array in TypeScript, taking into account the property

I'm currently working on a small Angular project that involves managing an array of receipt items such as Coke, Fanta, Pepsi, Juice, etc. Each receipt item has its own price and quantity listed. receiptItems: Array<ReceiptItem>; Here is the st ...

Tips for sending arguments to translations

I am currently implementing vuejs 3 using TS. I have set up my translation files in TypeScript as shown below: index.ts: export default { 'example': 'example', } To use the translations, I simply do: {{ $t('example') }} N ...

Error encountered when providing valid data types as arguments in a React/Typescript function

I am facing an issue when passing a string variable to a function. To address this, I have created an interface called MyMessageProps where I declare the message as a string. Subsequently, the function MyMessage utilizes this interface to return with the ...

The Element is Unfamiliar - Application with Multiple Modules

I seem to be facing an issue with how my modules are structured, as I am unable to use shared components across different modules. Basically, I have a Core module and a Feature module. The Core module contains components that I want to share across multip ...

Exploring Immediately Invoked Function Expressions in TypeScript

I came across an interesting article on self-invoking functions in JavaScript by Minko Gechev. This article teaches us how to create a JavaScript function that calls itself immediately after being initialized. I am curious about how we can achieve this in ...

Calling GraphQL mutations in ReactPGA

I encountered a 400 Error when making a call from the client to server, and I'm not sure where to start troubleshooting. Oddly enough, when I only include the "id" parameter in the request, everything works fine. However, as soon as I add the additio ...

Getting just the outer edges of intricate BufferGeometry in Three.js

Currently, I am immersed in a project that involves zone creation and collision detection using Three.js. The primary objective is for my application to effectively manage collisions and produce a BufferGeometry as the final output. My aim is to visually r ...