An error may occur when Typescript is instantiated with a varying subtype of constraint

I am encountering the "could be instantiated with a different subtype of constraint" error when trying to return a result that should match the expected type of a function. Despite removing irrelevant details, I'm struggling to pinpoint what exactly I'm doing wrong in my code snippet:

type User = { }

interface BasePageProps {
    user: User
}

type GetServerSidePropsResult<P> =
  | { props: P }

type PropsWithUser = <TProps extends BasePageProps>(
    callback: (user: User) => Promise<Omit<TProps, 'user'>>
) => Promise<GetServerSidePropsResult<TProps>>

export const testFunc: PropsWithUser = async (callback) => {
    const user = {}
    return { props: {
            user,
            ...(await callback(user))
        } }
}

Here is the exact error message I am facing:

'{ user: {}; } & Omit<TProps, "user">' can be assigned to the constraint of type 'TProps', however, it's possible that 'TProps' could be initialized with a different subtype of constraint 'BasePageProps'.

You can view this example on TS Playground here.

Why does the potential instantiation of TProps with a different subtype pose a problem? And how can I go about resolving this issue?

P.S.: Although these types are derived from Next.js, it is pertinent to note that the issue at hand is not specific to Next.js itself, hence please avoid linking its tag to this question.

Answer №1

Here is the correct signature for your function:

type PropsWithUser = <TProps extends BasePageProps>(
    callback: (user: User) => Promise<Omit<TProps, 'user'>>
) => Promise<GetServerSidePropsResult<BasePageProps & Omit<TProps, 'user'>>>

You can also simplify it by avoiding repetition:

type PropsWithUser = <TProps extends BasePageProps, TO = Omit<TProps, 'user'>(
    callback: (user: User) => Promise<TO>
) => Promise<GetServerSidePropsResult<BasePageProps & TO>>

To understand why the compiler raises an error, consider this example where a type TProps that extends

BasePageProps</code fails the function's result typecheck:</p>
<pre class="lang-javascript"><code>type User = { }

type AnotherUser = { a: string }

interface TProps {
    user: AnotherUser
}

interface BasePageProps {
    user: User
}

type Eq = TProps extends BasePageProps ? true : false // type Eq = true

type PropsWithUser = <TProps extends BasePageProps>(
    callback: (user: User) => Promise<Omit<TProps, 'user'>>
) => Promise<GetServerSidePropsResult<TProps>>

Check out this TS playground

Your function should return a result with type

Promise<{ props: { user: AnotherUser, ... } }>
, which it currently does not.

The error message states:

'{ user: {}; } & Omit<TProps, "user">' is assignable to the constraint of type 'TProps', but 'TProps' could be instantiated with a different subtype of constraint 'BasePageProps'

type User = { }

interface BasePageProps {
    user: User
}

type AnotherUser = { a: string }

interface ConcreteTProps {
    user: AnotherUser
}

// { user: {}; } & Omit<TProps, "user"> is assignable
// to the constraint of type TProps (i.e. BasePageProps)
const a: BasePageProps = { user: {} }

// However, 'TProps' could be instantiated with a different 
// subtype of constraint 'BasePageProps' (e.g. ConcreteTProps)
// This subtype cannot be assigned with { user: User }
const b: ConcreteTProps = { user: {} } // error

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

Retrieving the value of a selected option in Angular

I have the following dropdown select in my HTML and I am currently retrieving the text content of the selected option. How can I access the value attribute instead? Here is the dropdown select: <form [formGroup]="angForm" class="form-inline my-5 my-l ...

Convert Time: segment time devoted to the main content from the time dedicated to advertisements

Can anyone assist me with solving a math problem? Let's consider two lists or arrays: Content Array 0-50 = C1 50-100 = C2 AD Array 10-20 = A1 30-60 = A2 80-140 = A3 The desired output should be: 0-10 = C1 10-20 = A1 20-30 = C1 30-60 = A2 60-80 = C ...

Having trouble dynamically rendering a Component using Object.entries

Looking to streamline my code, I am trying to iterate over a series of MUI rows using a loop and Object.entries. However, when attempting to extract the value of each separate Object, I encounter the following error: TS7053: Element implicitly has an &ap ...

Retrieving decimal value from a given string

Currently, I am working with Google Maps and encountering an issue with distance values being returned as strings like 1,230.6 km. My goal is to extract the floating number 1230.6 from this string. Below is my attempted solution: var t = '1,234.04 km ...

Creating a custom utility type in TypeScript for serializing an array of objects: What you need to know

Imagine I have the following specified object: type Test = { date: Date num: number str: string } In this object, there is a Date type that needs to be converted into a string ("serialized"). To achieve this, I came up with the concept of a Generic ...

How do AppComponent and @Component relate to each other in AngularJs 2?

Recently, I came across the file app.component.ts in Example and found some interesting code. The link to the example is: here. Here's a snippet of the code: import { Component } from '@angular/core'; export class Hero { id: number; na ...

Having trouble retrieving a value from the img.onload event handler. A 'boolean' type error is being thrown, indicating it cannot be assigned to type '(this: GlobalEventHandlers, ev: Event) => any'

In my Angular application, I have implemented a method that verifies the size and dimensions of an image file and returns either false or true based on the validation result. Below is the code snippet for this function: checkFileValidity(file: any, multipl ...

An issue with the validation service has been identified, specifically concerning the default value of null in

Using Angular 10 and Password Validator Service static password(control: AbstractControl) { // {6,100} - Check if password is between 6 and 100 characters // (?=.*[0-9]) - Ensure at least one number is present in the strin ...

Assign a value to a date field in Aurelia

<input class="" type="date" id="Broken" value.bind="dateval"> The current value of dateval is 2021-04-08T10:05:19.988Z. Is there a way to set a default date for the date input field above? ...

Is there a method to run code in the parent class right after the child constructor is called in two ES6 Parent-Child classes?

For instance: class Parent { constructor() {} } class Child { constructor() { super(); someChildCode(); } } I need to run some additional code after the execution of someChildCode(). Although I could insert it directly there, the requirement is not to ...

How can I nest a kendo-grid within another kendo-grid and make them both editable with on-cell click functionality?

I am facing an issue with my 2 components - trial1 (parent kendo-grid) and trial2 (child kendo-grid). Inside the template of trial1, I referenced the sub-grid component trial2. However, I am encountering an error where trial2 is not recognized inside trial ...

How do I create a generic function in TypeScript that adjusts its behavior based on the input argument?

Is there a way to create a generic function that can accept generic arguments like Data<string, number>? Take a look at this code snippet: interface Data<T,R> { a:T; c:R; } function foo( data: Data<string, number> ){ return t ...

Problem with Typescript: The type '{ x;y }' is required to have a '[Symbol.iterator]()' method

Just starting out with Typescript and tackling the task of converting a React project from JavaScript to TypeScript. I've been diving into various posts for guidance, but I feel like I'm going in circles. Any assistance would be greatly appreci ...

Is there a way for me to input only the value and have TypeScript automatically determine the key of an object?

My challenge lies in having an object with string keys, but I do not want them to remain as strings. Instead, I desire the keys to be the exact values of the object. This means that I must input the value of the object accordingly to meet certain criteria. ...

"TypeScript function returning a boolean value upon completion of a resolved promise

When working on a promise that returns a boolean in TypeScript, I encountered an error message that says: A 'get' accessor must return a value. The code snippet causing the issue is as follows: get tokenValid(): boolean { // Check if curre ...

What is the purpose of the .default() method being added to the class constructor in transpiled Typescript code

In TypeScript, I have the following code snippet to create an instance of ConnectRoles Middleware in Express: let user = new ConnectRoles(config); The middleware initialization is expected to be a simple call to a constructor. However, after transpiling, ...

Is there a way to automatically validate v-forms inside a v-data-table when the page loads?

In my data entry form, I have utilized a v-data-table with each column containing a v-form and v-text-field for direct value updates. My goal is to validate all fields upon page load to identify any incorrect data inputs. However, I am facing challenges in ...

TS: How can we determine the type of the returned object based on the argument property?

Assume we have the following data types type ALL = 'AA' | 'BB' | 'CC'; type AA = { a: number; }; type BB = { b: string; }; type CC = { c: boolean; }; type MyArg = { type: ALL }; I attempted to create a mapping between type n ...

Leverage process.env variables within your next.config.js file

Currently, I have an application running on NextJS deployed on GCP. As I set up Continuous Deployment (CD) for the application, I realized that there are three different deploy configurations - referred to as cd-one.yaml, cd-two.yaml, and cd-three.yaml. Ea ...

The 'subscribe' property is not available on the type '() => Observable<any>'

File for providing service: import { Observable } from 'rxjs/Rx'; import { Http, Response} from '@angular/http'; import { Injectable } from '@angular/core'; import 'rxjs/add/operator/Map'; @Injectable() export clas ...