The return type loses its value when the argument is of a generic nature

Check out this code snippet from the playground.

class Smth {
    public self(): this {
        return this
    }

    public add() {
        return this as this & { func(): Smth }
    }
}

function f(x: Smth) {
    const y = x.add()    // Smth & { func(): Smth; }
    y.func()             // Ok
    const z = y.self()   // Smth & { func(): Smth; }
    z.func()             // Ok
}

function g<S extends Smth>(x: S) {
    const y = x.add()    // S & { func(): Smth; }
    y.func()             // Ok
    const z = y.self()   // S
    z.func()             // Error: Property 'func' does not exist on type 'S'.
}

The functions f and g exhibit different behavior where g is generic:

function f(x: Smth) {
function g<S extends Smth>(x: S) {

However, a discrepancy arises at the line

const z = y.self()

In a non-generic function, self correctly returns this, but in a generic function z ends up being just S instead of S & { func(): Smth; }.

How can I ensure that after calling y.self() in the generic function, the correct type S & { func(): Smth; } is returned?

Answer №1

You have the potential to achieve it, however, utilizing polymorphic this may not be the way. The solution lies in making self generic and allowing this to be inferred at the call site.

class Smth {
    public self(): this {
    //public self<T>(this:T): T {
        return this
    }

    public add() {
        return this as this & { func(): Smth }
    }
}

function f(x: Smth) {
    const y = x.add()    // Smth & { func(): Smth; }
    y.func()             // Ok
    const z = y.self()   // Smth & { func(): Smth; }
    z.func()             // Ok
}

function g<S extends Smth>(x: S) {
    const y = x.add()    // S & { func(): Smth; }
    y.func()             // Ok
    const z = y.self()   // S
    z.func()             // Error: Property 'func' does not exist on type 'S'.
}

Playground Link

The reason behind why polymorphic this doesn't function in this particular scenario remains unclear. It is worth considering reaching out via GitHub to address any issues.

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

Comparing two generic objects with nested collections: a guide

I have been striving to create a method that can efficiently compare two identical objects to check if their values match. Currently, I am facing a challenge in comparing System.Collection.Generic objects like Dictionary, HashSet, LinkedList, Stack, and s ...

What is the process for retrieving isolated scope values from typescript directives within a typescript controller class?

As I work with a Typescript directive class and controller class, I am facing an issue. I need to set up a watch on an isolated scope variable within the Typescript controller class, but I seem to be unable to access these isolated scope variables. How can ...

Navigating a JSON object with TypeScript in Angular 2: A Step-by-Step Guide

I'm relatively new to Angular2 and I am currently grappling with looping through a JSON object retrieved from a GET request. Here's the JSON object in question: { Results: [{ Time: "2017-02-11T08:15:01.000+00:00", Id: "data- ...

Error encountered during TypeScript compilation: Module 'fs' not found

I encountered an issue: TSError: ⨯ Unable to compile TypeScript: server/src/test/test.ts(2,45): error TS2307: Cannot find module 'fs' Every time I execute this particular test import "mocha" import { writeFileSync, readFileSync } from &a ...

Forever waiting: Angular HTTP requests stuck in limbo

Switching from MongoDB to MySQL for my Angular/NodeJS project has brought about some challenges, particularly with handling HTTP Requests. I have tried GET and POST requests, but GET always remains pending and eventually fails, while POST does not successf ...

Issue with Angular 6 where data is not binding to the UI on initialization

I am struggling with binding dynamic data to the UI and Data tables on my website. Despite trying various methods, I have not been able to achieve success. Currently, I am using the smart admin latest theme for development. When I make a call to the API, ...

injecting a variable from the configuration service into a TypeScript decorator

I am interested in setting up a scheduled task for my NestJs application to run at regular intervals. I found information on how to use intervals in the NestJs documentation. Since my application uses configuration files, I want to keep the interval value ...

What is the best way to sort through an Array of photo filenames?

https://i.sstatic.net/04cws.pngI have a list of image names that contain UUIDs. images [ "auditid_626_UUID_666666_time__1582577405550.jpg", "auditid_626_UUID_999999_time__1582577405554.jpg", "auditid_626_UUID_999999_time__15825 ...

Extracting values from dynamically named properties in ES6 using object destructuring

let currentFilter: Product = { name: 'iphone', price: 30, createdDate: '11-11-2020' } My code is structured around a specific filter. The filter data is structured in the following format: I have a table with different filters. ...

Guide to implementing a specified directive value across various tags in Angular Material

As I delve into learning Angular and Material, I have come across a challenge in my project. I noticed that I need to create forms with a consistent appearance. Take for example the registration form's template snippet below: <mat-card> <h2 ...

Tips for working with Typescript: utilizing the default value for a non-existent computed property

When utilizing Computed Property in javascript, I can structure my code as follows const default_values = {a:"debug",b:"info",c:"warning"}; function execute(y) { let x = default_values[y] || default_values.a /* if y is no ...

Assign an appropriate label to this sonarqube input field

Sonarqube flagged an issue with the following line of code: <div class="dropdown-language"> <label>{{'GENERALE.LINGUA' | translate }}</label> <select #langSelect (change)="translate.use(langSe ...

Issue with ng-multiselect-dropdown where clearing selected items programmatically does not visually work as expected

Utilizing the ng-multiselect-dropdown, I have encountered an issue where deselecting an option within the object itself clears the selected items visually and in the variable array. However, when programmatically clearing the selectedItems, the variable a ...

The process of incorporating user properties into the output of a Service Bus topic from a Javascript Azure Function

I'm currently developing a TypeScript Azure Function that utilizes an Azure Service Bus topic as its output. Although I am able to send messages successfully, I have encountered difficulties in setting custom metadata properties for the message. In m ...

The MUI component received props that were not defined

I created a customized MUI card with the intention of applying a dark background when the darkBg prop is passed. However, I've encountered an issue where despite passing darkBg as true, the card's background remains white. To troubleshoot, I atte ...

The front end is displaying an empty object, although it is showing up when logged in the console using ngFor

I'm currently enrolled in a tutorial course and I've hit a roadblock at this stage. I want to display the properties of the Product on both the console.log and the web page. Strangely, the console.log is showing the product correctly, but the fro ...

Encountered an issue with valid types while executing the following build

Encountering an error when attempting to run the next build process. https://i.stack.imgur.com/qM3Nm.png Tried various solutions including updating to ES6, switching the module to commonJs, downgrading webpack to version 4 with no success. The only worka ...

Can the response data in TypeScript (React) be altered if the actual data structure doesn't match the defined type?

Currently in the process of developing an online retail application for my organization. I have encountered a specific issue that I'd like to address: content: [ isAvailable: boolean; isSoldOut: boolean; product: { id: string; ...

Updating nullable columns in typeorm entities: a step-by-step guide

Within my typeorm entity, there is a column defined as: @Column({ type: 'bigint', nullable: true, }) lockedTimestamp?: number; In my nest.js code, I am trying to handle it like this: if (...) {entity.lockedTimesta ...

Retrieving a complete array of countries from the mat-country-select package

I'm currently working with reactive forms in my Angular project and utilizing mat-country-select to display a list of countries in a select dropdown within my child FormComponent. <mat-select-country class="full-width" ...