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

What is the process for deserializing a JSON-wrapped collection property into a generic class

The Challenge Many APIs that return RESTful JSON data wrap collections within an object. This object typically includes a property indicating the number of items in the collection. Consider the following examples: { "animals": [ {"name": "Ra ...

unable to locate the nested routes in the folder for remix

Hey there, I've been using the remix to create a basic page and I'm trying to organize the routes using folders. Here is my project directory: - app/ - root.tsx - examples/ - route.tsx - child1/ - account.tsx In the examples di ...

Implementing type inference for response.locals in Express with TypeScript

I need to define types for my response.locals in order to add data to the request-response cycle. This is what I attempted: // ./types/express/index.d.ts declare global { declare namespace Express { interface Response { locals: { ...

I am eager to learn how to integrate the "fs" module from Node.js into an Electron project powered by Angular

As I venture into writing my first desktop app using Electron and Angular5, I have encountered a roadblock while working with the fs module. Despite importing fs correctly (without errors in Visual Studio Code and with code completion), I faced an issue wh ...

Is it possible to assign an interface to an object property in TypeScript?

I am currently working with an object that looks like this: export class Section{ singleLabel:string; pluralLabel:string; index:number; dataInterface:Interface; } My goal is to assign an interface to the dataInterface field, as I need to use the S ...

What is the process for retrieving the GitHub username in the GitHub OAuth Next.js sign-in callback in order to store it in a database?

1. Detail the issue I am facing a challenge while developing a Full Stack Website using Next.js and Typescript. Specifically, I am having difficulty persisting the Github Username in the database when a user signs in via Github OAuth. Should I consider st ...

Evaluating function declaration - comparing interface to type alias

Here is a function that I need to create a validator for: function (n: number) { return {s: n}; } I have come across two options for creating the validator: Option 1: Interface interface ValidatorFnInterface { (n: number): { [key: strin ...

Unable to remove loading.tsx file

Currently tackling a project using Next.js, I decided to include loading.tsx within the app directory. However, upon attempting to delete it, an error crops up: Caused by: The system cannot find the file specified. (os error 2) The import trace for the r ...

When deploying my Angular project, I am unable to access my files

I have been facing challenges while trying to deploy my web application with the frontend being Angular. The issue I am encountering is that I cannot access my JSON file located in the assets folder. Below is the function I am using to retrieve data from ...

Creating a variable that is not defined and then converting it into

I have an issue with a function that returns an Observable. The problem is that when the function is called, the parameter works fine, but its value becomes undefined within the Observable. This is the function in question: import {Observable} from &apos ...

Setting up an empty array as a field in Prisma initially will not function as intended

In my current project using React Typescript Next and prisma, I encountered an issue while trying to create a user with an initially empty array for the playlists field. Even though there were no errors shown, upon refreshing the database (mongodb), the pl ...

Tips for soothing the TypeScript compiler

It seems like TypeScript is heavily influenced by Microsoft's interpretation of the DOM and JavaScript. But what if I'm not concerned with Internet Explorer and Edge? Unfortunately, I'm encountering issues with TypeScript... For instance, w ...

Typescript is unable to locate the .d.ts files

Working on a personal project and came across a library called merge-graphql-schemas. Since the module lacks its own typings, I created a file at src/types/merge-graphql-schemas.d.ts In merge-graphql-schemas.d.ts, I added: declare module "merge-graphql-s ...

An issue occurred with building deployments on Vercel due to a typing error

When attempting to deploy my build on Vercel, I encountered an error. The deployment works fine locally, but when trying to build it on vercel, the following error occurs: [![Type error: Type '(ref: HTMLDivElement | null) => HTMLDivElement | null&a ...

Encountering a Typescript issue with mongoose

Working with node.js and various email addresses, I encountered a compile error: TS2345: Argument of type '(error: any, document: any) => void' is not assignable to parameter of type '(err: any) => void'. This error occurs at the l ...

How can I subtract a value from my array in Angular?

I've been troubleshooting this problem for a while now and I'm hoping that someone here can assist me with finding a solution. The issue at hand involves an array object containing various values such as id, title, amountCounter. Specifically, t ...

Tips for preventing repetition of code in multiple entry points in Rollup

My goal is to use rollup to process a group of input files and generate multiple output files in the dist directory that all have some common code shared between them. Below is my current rollup configuration: import path from 'path'; import pat ...

Is there a way to establish a pre-defined key in a mat-table?

I am fetching data from an API and I need to display it in a key-value format on a mat table. The keys are predefined and not provided by the API. The data retrieved from the API is shown here: image1 I want to display it on a mat table like this: mat ta ...

Utilizing Class Types in Generics with TypeScript

Struggling to implement a factory method based on the example from the documentation on Using Class Types in Generics, but hitting roadblocks. Here's a simplified version of what I'm attempting: class Animal { legCount = 4; constructor( ...

Can webpack effectively operate in both the frontend and backend environments?

According to the information provided on their website, packaging is defined as: webpack serves as a module bundler with its main purpose being to bundle JavaScript files for usage in a browser. Additionally, it has the ability to transform, bundle, or ...