Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

get property return type inferred incorrectly from 'this' type, when other methods exist #61361

Open
martaver opened this issue Mar 6, 2025 · 3 comments

Comments

@martaver
Copy link

martaver commented Mar 6, 2025

🔎 Search Terms

get property
get accessor
incorrectly inferred type
incorrectly inferred return type
this
ThisType

🕗 Version & Regression Information

This is the behaviour in every version I tried, and I reviewed the FAQ for entries about 'get accessors'

Before 4.8.4, even stand-alone 'get' properties didn't infer their type correctly.

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.8.2#code/PQKhCgAIUhJSAWBDAbgU0kyAzArgOwGMAXASwHt9JjzJCkAHY3AJw2IXYE8GMADACp9I5bJirkARgCs0JSABM5AGyQskZSpBSkspfNjRsiaAHRQYAQWLVOkAM5IAtu1IuANHEgB3JPhs0kAws5DpKthh4RJpUWMQ8-AAKwhwaXvRU+rLyWhwYUtnEAOT2kEUcpPZF1Anm0MDg4MDAkADipOixDsQapIQ1vJCJ4FEkFFTB5Az2ADyJkGgAHsRo+AqlBXLEAHwAFACUkADeUJBnbMwsVCdnt7fNcAZGEQMYAiJifiIyW56TYfoAOZDTClIqTabVLSkYhgipVV6QfQrK5IZTKLh1O63SY0ABcOAIYy0MwEewA+rjyAT3gAySACBCVAQJUmQelHIIhaYE+YAX22hxu2POaEuVEpIUCSFKAlOIr58sgisVTTAFkgAHVOFR4EpCKo2JgyoCxdUIUZ4iIqHlvoVbGkLqx8KUsCg0bhIiEnC8sls0ApEXxkp5bU6rojKtAkU8WGxA4RyHGthi8RYGk0WizBqIypJVAhqlGivhcE5JEYiuZEy6bN4kwBrIGQAC8XKms05U2IBNL5eeAoOpipu2FZ1NNnzSAQB2OSru4ZtTPsw+5K+7Sr57nAfP2jVAEGjAAlyN40OgWJ5vDrMIRE04GH5SAHIJIuOJ3+Q8ixIC4OOR1lDOxF0RXM+CnBBhAre80FKPg-C4Pg03qfcswSD48wLap7AQchcGUQMKzKPsKxYIpPEkXAbGLBCq3AGt7EnEIG1WVt22mGYuyYXsy1I5U9n2Vcv3IUclWwcgRKFedbhAgBGTdtzuCdXwLWcx2xED4SE6ZTA3O4tx3fYgA

💻 Code

/**
 * I have a function to capture the type `T` of an object declaration via inference.
 * At the same time, I want to provide the function a type `P` that I can inject on the object's 'this' type.
 */

// Given a static type P
function props<P extends object>() {
    return {
        // Infer the type T of an object, providing P as 'props' on its 'this' type internally.
        proto: function <T>(_proto: T & ThisType<T & { props: P }>) {
        return _proto as T
        }
    }
}

/**
 * When I declare a 'get' property on the object that returns a value from the injected type `P`, the return type is * inferred correctly:
 */

// Type of 'blah' is 'number'.
const working = props<{ opt: number }>().proto({
    get blah() {
        return this.props.opt
    },
})

/**
 * However, when accompanied by any other methods, the return type of `blah` becomes `any`:
 */

// Type of 'blah' should be 'number', but is 'any'.
const broken = props<{ opt: number }>().proto({
    foo() {
        return 1
    },
    get blah() {
        return this.props.opt
    },
})

🙁 Actual behavior

By itself, the 'blah' get accessor infers its return type from this.props.opt correctly, but when another method is added to the same object, its type changes to any.

🙂 Expected behavior

The inferred return type of blah get accessor should not be changed by adding a method to the object.

Additional information about the issue

No response

@Andarist
Copy link
Contributor

Andarist commented Mar 6, 2025

The problem here is that getters are resolved eagerly even though they might have a context-sensitive dependency on this. It's not something that methods suffer from even though they might depend on this (TS playground):

const thisWorksFine = props<{ opt: number }>().proto({
  foo() {
    return 1;
  },
  blah() {
    return this.props.opt;
  },
});

That's because they are deferred by nature. So the return type of that blah method can be type-checked when this type is already more well-established.

A strong duplicate of #47150
A duplicate (in slight disguise) of #49511
Slightly related to #58484

@martaver
Copy link
Author

martaver commented Mar 7, 2025

What could be more well-established than a static type { opt: number }? 😃

Thanks for the links, I should have spent longer looking for dupes... do you want me to close this issue and track one of these others ones? Which would be the one to follow?

@Andarist
Copy link
Contributor

Andarist commented Mar 7, 2025

Tbf, one of the first ones I linked to should be closed in the favor of the other. They look like duplicates to me - but it’s up to @RyanCavanaugh to decide. So I can’t tell which one you should follow. You can always follow both, they are not noisy anyway :p

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants