TypeScript
TypeScript copied to clipboard
get property return type inferred incorrectly from 'this' type, when other methods exist
π 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
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 https://github.com/microsoft/TypeScript/issues/47150 A duplicate (in slight disguise) of https://github.com/microsoft/TypeScript/issues/49511 Slightly related to https://github.com/microsoft/TypeScript/issues/58484
What could be more well-established than a static type { opt: number }? :smiley:
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?
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
Omnibus tracked at #47599. An alternative workaround is to write
foo: () => {
return 1;
},
This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes.