mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Instantiate getter when infering setter parameter value (#43564)
* Instantiate getter when infering setter parameter value * Use esnext on tests * Instantiate for JsDoc and getter from body * PR comments * Updated baseline
This commit is contained in:
parent
167ebcd93b
commit
f67ee44379
@ -9082,42 +9082,36 @@ namespace ts {
|
||||
const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
|
||||
const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
|
||||
|
||||
const setterType = getAnnotatedAccessorType(setter);
|
||||
|
||||
// For write operations, prioritize type annotations on the setter
|
||||
if (writing) {
|
||||
const setterParameterType = getAnnotatedAccessorType(setter);
|
||||
if (setterParameterType) {
|
||||
const flags = getCheckFlags(symbol);
|
||||
if (flags & CheckFlags.Instantiated) {
|
||||
const links = getSymbolLinks(symbol);
|
||||
return instantiateType(setterParameterType, links.mapper);
|
||||
}
|
||||
return setterParameterType;
|
||||
}
|
||||
if (writing && setterType) {
|
||||
return instantiateTypeIfNeeded(setterType, symbol);
|
||||
}
|
||||
// Else defer to the getter type
|
||||
|
||||
if (getter && isInJSFile(getter)) {
|
||||
const jsDocType = getTypeForDeclarationFromJSDocComment(getter);
|
||||
if (jsDocType) {
|
||||
return jsDocType;
|
||||
return instantiateTypeIfNeeded(jsDocType, symbol);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to see if the user specified a return type on the get-accessor.
|
||||
const getterReturnType = getAnnotatedAccessorType(getter);
|
||||
if (getterReturnType) {
|
||||
return getterReturnType;
|
||||
const getterType = getAnnotatedAccessorType(getter);
|
||||
if (getterType) {
|
||||
return instantiateTypeIfNeeded(getterType, symbol);
|
||||
}
|
||||
|
||||
// If the user didn't specify a return type, try to use the set-accessor's parameter type.
|
||||
const setterParameterType = getAnnotatedAccessorType(setter);
|
||||
if (setterParameterType) {
|
||||
return setterParameterType;
|
||||
if (setterType) {
|
||||
return setterType;
|
||||
}
|
||||
|
||||
// If there are no specified types, try to infer it from the body of the get accessor if it exists.
|
||||
if (getter && getter.body) {
|
||||
return getReturnTypeFromBody(getter);
|
||||
const returnTypeFromBody = getReturnTypeFromBody(getter);
|
||||
return instantiateTypeIfNeeded(returnTypeFromBody, symbol);
|
||||
}
|
||||
|
||||
// Otherwise, fall back to 'any'.
|
||||
@ -9135,6 +9129,15 @@ namespace ts {
|
||||
return anyType;
|
||||
}
|
||||
return undefined;
|
||||
|
||||
function instantiateTypeIfNeeded(type: Type, symbol: Symbol) {
|
||||
if (getCheckFlags(symbol) & CheckFlags.Instantiated) {
|
||||
const links = getSymbolLinks(symbol);
|
||||
return instantiateType(type, links.mapper);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
function getBaseTypeVariableOfClass(symbol: Symbol) {
|
||||
|
||||
49
tests/baselines/reference/genericSetterInClassType.js
Normal file
49
tests/baselines/reference/genericSetterInClassType.js
Normal file
@ -0,0 +1,49 @@
|
||||
//// [genericSetterInClassType.ts]
|
||||
module Generic {
|
||||
class C<T> {
|
||||
get y(): T {
|
||||
return 1 as never;
|
||||
}
|
||||
set y(v) { }
|
||||
}
|
||||
|
||||
var c = new C<number>();
|
||||
c.y = c.y;
|
||||
|
||||
class Box<T> {
|
||||
#value!: T;
|
||||
|
||||
get value() {
|
||||
return this.#value;
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
this.#value = value;
|
||||
}
|
||||
}
|
||||
|
||||
new Box<number>().value = 3;
|
||||
}
|
||||
|
||||
//// [genericSetterInClassType.js]
|
||||
var Generic;
|
||||
(function (Generic) {
|
||||
class C {
|
||||
get y() {
|
||||
return 1;
|
||||
}
|
||||
set y(v) { }
|
||||
}
|
||||
var c = new C();
|
||||
c.y = c.y;
|
||||
class Box {
|
||||
#value;
|
||||
get value() {
|
||||
return this.#value;
|
||||
}
|
||||
set value(value) {
|
||||
this.#value = value;
|
||||
}
|
||||
}
|
||||
new Box().value = 3;
|
||||
})(Generic || (Generic = {}));
|
||||
63
tests/baselines/reference/genericSetterInClassType.symbols
Normal file
63
tests/baselines/reference/genericSetterInClassType.symbols
Normal file
@ -0,0 +1,63 @@
|
||||
=== tests/cases/conformance/classes/members/classTypes/genericSetterInClassType.ts ===
|
||||
module Generic {
|
||||
>Generic : Symbol(Generic, Decl(genericSetterInClassType.ts, 0, 0))
|
||||
|
||||
class C<T> {
|
||||
>C : Symbol(C, Decl(genericSetterInClassType.ts, 0, 16))
|
||||
>T : Symbol(T, Decl(genericSetterInClassType.ts, 1, 12))
|
||||
|
||||
get y(): T {
|
||||
>y : Symbol(C.y, Decl(genericSetterInClassType.ts, 1, 16), Decl(genericSetterInClassType.ts, 4, 9))
|
||||
>T : Symbol(T, Decl(genericSetterInClassType.ts, 1, 12))
|
||||
|
||||
return 1 as never;
|
||||
}
|
||||
set y(v) { }
|
||||
>y : Symbol(C.y, Decl(genericSetterInClassType.ts, 1, 16), Decl(genericSetterInClassType.ts, 4, 9))
|
||||
>v : Symbol(v, Decl(genericSetterInClassType.ts, 5, 14))
|
||||
}
|
||||
|
||||
var c = new C<number>();
|
||||
>c : Symbol(c, Decl(genericSetterInClassType.ts, 8, 7))
|
||||
>C : Symbol(C, Decl(genericSetterInClassType.ts, 0, 16))
|
||||
|
||||
c.y = c.y;
|
||||
>c.y : Symbol(C.y, Decl(genericSetterInClassType.ts, 1, 16), Decl(genericSetterInClassType.ts, 4, 9))
|
||||
>c : Symbol(c, Decl(genericSetterInClassType.ts, 8, 7))
|
||||
>y : Symbol(C.y, Decl(genericSetterInClassType.ts, 1, 16), Decl(genericSetterInClassType.ts, 4, 9))
|
||||
>c.y : Symbol(C.y, Decl(genericSetterInClassType.ts, 1, 16), Decl(genericSetterInClassType.ts, 4, 9))
|
||||
>c : Symbol(c, Decl(genericSetterInClassType.ts, 8, 7))
|
||||
>y : Symbol(C.y, Decl(genericSetterInClassType.ts, 1, 16), Decl(genericSetterInClassType.ts, 4, 9))
|
||||
|
||||
class Box<T> {
|
||||
>Box : Symbol(Box, Decl(genericSetterInClassType.ts, 9, 14))
|
||||
>T : Symbol(T, Decl(genericSetterInClassType.ts, 11, 14))
|
||||
|
||||
#value!: T;
|
||||
>#value : Symbol(Box.#value, Decl(genericSetterInClassType.ts, 11, 18))
|
||||
>T : Symbol(T, Decl(genericSetterInClassType.ts, 11, 14))
|
||||
|
||||
get value() {
|
||||
>value : Symbol(Box.value, Decl(genericSetterInClassType.ts, 12, 19), Decl(genericSetterInClassType.ts, 16, 9))
|
||||
|
||||
return this.#value;
|
||||
>this.#value : Symbol(Box.#value, Decl(genericSetterInClassType.ts, 11, 18))
|
||||
>this : Symbol(Box, Decl(genericSetterInClassType.ts, 9, 14))
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
>value : Symbol(Box.value, Decl(genericSetterInClassType.ts, 12, 19), Decl(genericSetterInClassType.ts, 16, 9))
|
||||
>value : Symbol(value, Decl(genericSetterInClassType.ts, 18, 18))
|
||||
|
||||
this.#value = value;
|
||||
>this.#value : Symbol(Box.#value, Decl(genericSetterInClassType.ts, 11, 18))
|
||||
>this : Symbol(Box, Decl(genericSetterInClassType.ts, 9, 14))
|
||||
>value : Symbol(value, Decl(genericSetterInClassType.ts, 18, 18))
|
||||
}
|
||||
}
|
||||
|
||||
new Box<number>().value = 3;
|
||||
>new Box<number>().value : Symbol(Box.value, Decl(genericSetterInClassType.ts, 12, 19), Decl(genericSetterInClassType.ts, 16, 9))
|
||||
>Box : Symbol(Box, Decl(genericSetterInClassType.ts, 9, 14))
|
||||
>value : Symbol(Box.value, Decl(genericSetterInClassType.ts, 12, 19), Decl(genericSetterInClassType.ts, 16, 9))
|
||||
}
|
||||
67
tests/baselines/reference/genericSetterInClassType.types
Normal file
67
tests/baselines/reference/genericSetterInClassType.types
Normal file
@ -0,0 +1,67 @@
|
||||
=== tests/cases/conformance/classes/members/classTypes/genericSetterInClassType.ts ===
|
||||
module Generic {
|
||||
>Generic : typeof Generic
|
||||
|
||||
class C<T> {
|
||||
>C : C<T>
|
||||
|
||||
get y(): T {
|
||||
>y : T
|
||||
|
||||
return 1 as never;
|
||||
>1 as never : never
|
||||
>1 : 1
|
||||
}
|
||||
set y(v) { }
|
||||
>y : T
|
||||
>v : T
|
||||
}
|
||||
|
||||
var c = new C<number>();
|
||||
>c : C<number>
|
||||
>new C<number>() : C<number>
|
||||
>C : typeof C
|
||||
|
||||
c.y = c.y;
|
||||
>c.y = c.y : number
|
||||
>c.y : number
|
||||
>c : C<number>
|
||||
>y : number
|
||||
>c.y : number
|
||||
>c : C<number>
|
||||
>y : number
|
||||
|
||||
class Box<T> {
|
||||
>Box : Box<T>
|
||||
|
||||
#value!: T;
|
||||
>#value : T
|
||||
|
||||
get value() {
|
||||
>value : T
|
||||
|
||||
return this.#value;
|
||||
>this.#value : T
|
||||
>this : this
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
>value : T
|
||||
>value : T
|
||||
|
||||
this.#value = value;
|
||||
>this.#value = value : T
|
||||
>this.#value : T
|
||||
>this : this
|
||||
>value : T
|
||||
}
|
||||
}
|
||||
|
||||
new Box<number>().value = 3;
|
||||
>new Box<number>().value = 3 : 3
|
||||
>new Box<number>().value : number
|
||||
>new Box<number>() : Box<number>
|
||||
>Box : typeof Box
|
||||
>value : number
|
||||
>3 : 3
|
||||
}
|
||||
58
tests/baselines/reference/genericSetterInClassTypeJsDoc.js
Normal file
58
tests/baselines/reference/genericSetterInClassTypeJsDoc.js
Normal file
@ -0,0 +1,58 @@
|
||||
//// [genericSetterInClassTypeJsDoc.js]
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
class Box {
|
||||
#value;
|
||||
|
||||
/** @param {T} initialValue */
|
||||
constructor(initialValue) {
|
||||
this.#value = initialValue;
|
||||
}
|
||||
|
||||
/** @type {T} */
|
||||
get value() {
|
||||
return this.#value;
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
this.#value = value;
|
||||
}
|
||||
}
|
||||
|
||||
new Box(3).value = 3;
|
||||
|
||||
|
||||
//// [genericSetterInClassTypeJsDoc-out.js]
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
class Box {
|
||||
#value;
|
||||
/** @param {T} initialValue */
|
||||
constructor(initialValue) {
|
||||
this.#value = initialValue;
|
||||
}
|
||||
/** @type {T} */
|
||||
get value() {
|
||||
return this.#value;
|
||||
}
|
||||
set value(value) {
|
||||
this.#value = value;
|
||||
}
|
||||
}
|
||||
new Box(3).value = 3;
|
||||
|
||||
|
||||
//// [genericSetterInClassTypeJsDoc-out.d.ts]
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
declare class Box<T> {
|
||||
/** @param {T} initialValue */
|
||||
constructor(initialValue: T);
|
||||
set value(arg: T);
|
||||
/** @type {T} */
|
||||
get value(): T;
|
||||
#private;
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
=== tests/cases/conformance/classes/members/classTypes/genericSetterInClassTypeJsDoc.js ===
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
class Box {
|
||||
>Box : Symbol(Box, Decl(genericSetterInClassTypeJsDoc.js, 0, 0))
|
||||
|
||||
#value;
|
||||
>#value : Symbol(Box.#value, Decl(genericSetterInClassTypeJsDoc.js, 3, 12))
|
||||
|
||||
/** @param {T} initialValue */
|
||||
constructor(initialValue) {
|
||||
>initialValue : Symbol(initialValue, Decl(genericSetterInClassTypeJsDoc.js, 7, 16))
|
||||
|
||||
this.#value = initialValue;
|
||||
>this.#value : Symbol(Box.#value, Decl(genericSetterInClassTypeJsDoc.js, 3, 12))
|
||||
>this : Symbol(Box, Decl(genericSetterInClassTypeJsDoc.js, 0, 0))
|
||||
>initialValue : Symbol(initialValue, Decl(genericSetterInClassTypeJsDoc.js, 7, 16))
|
||||
}
|
||||
|
||||
/** @type {T} */
|
||||
get value() {
|
||||
>value : Symbol(Box.value, Decl(genericSetterInClassTypeJsDoc.js, 9, 5), Decl(genericSetterInClassTypeJsDoc.js, 14, 5))
|
||||
|
||||
return this.#value;
|
||||
>this.#value : Symbol(Box.#value, Decl(genericSetterInClassTypeJsDoc.js, 3, 12))
|
||||
>this : Symbol(Box, Decl(genericSetterInClassTypeJsDoc.js, 0, 0))
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
>value : Symbol(Box.value, Decl(genericSetterInClassTypeJsDoc.js, 9, 5), Decl(genericSetterInClassTypeJsDoc.js, 14, 5))
|
||||
>value : Symbol(value, Decl(genericSetterInClassTypeJsDoc.js, 16, 14))
|
||||
|
||||
this.#value = value;
|
||||
>this.#value : Symbol(Box.#value, Decl(genericSetterInClassTypeJsDoc.js, 3, 12))
|
||||
>this : Symbol(Box, Decl(genericSetterInClassTypeJsDoc.js, 0, 0))
|
||||
>value : Symbol(value, Decl(genericSetterInClassTypeJsDoc.js, 16, 14))
|
||||
}
|
||||
}
|
||||
|
||||
new Box(3).value = 3;
|
||||
>new Box(3).value : Symbol(Box.value, Decl(genericSetterInClassTypeJsDoc.js, 9, 5), Decl(genericSetterInClassTypeJsDoc.js, 14, 5))
|
||||
>Box : Symbol(Box, Decl(genericSetterInClassTypeJsDoc.js, 0, 0))
|
||||
>value : Symbol(Box.value, Decl(genericSetterInClassTypeJsDoc.js, 9, 5), Decl(genericSetterInClassTypeJsDoc.js, 14, 5))
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
=== tests/cases/conformance/classes/members/classTypes/genericSetterInClassTypeJsDoc.js ===
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
class Box {
|
||||
>Box : Box<T>
|
||||
|
||||
#value;
|
||||
>#value : T
|
||||
|
||||
/** @param {T} initialValue */
|
||||
constructor(initialValue) {
|
||||
>initialValue : T
|
||||
|
||||
this.#value = initialValue;
|
||||
>this.#value = initialValue : T
|
||||
>this.#value : T
|
||||
>this : this
|
||||
>initialValue : T
|
||||
}
|
||||
|
||||
/** @type {T} */
|
||||
get value() {
|
||||
>value : T
|
||||
|
||||
return this.#value;
|
||||
>this.#value : T
|
||||
>this : this
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
>value : T
|
||||
>value : T
|
||||
|
||||
this.#value = value;
|
||||
>this.#value = value : T
|
||||
>this.#value : T
|
||||
>this : this
|
||||
>value : T
|
||||
}
|
||||
}
|
||||
|
||||
new Box(3).value = 3;
|
||||
>new Box(3).value = 3 : 3
|
||||
>new Box(3).value : number
|
||||
>new Box(3) : Box<number>
|
||||
>Box : typeof Box
|
||||
>3 : 3
|
||||
>value : number
|
||||
>3 : 3
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
// @target: esnext
|
||||
|
||||
module Generic {
|
||||
class C<T> {
|
||||
get y(): T {
|
||||
return 1 as never;
|
||||
}
|
||||
set y(v) { }
|
||||
}
|
||||
|
||||
var c = new C<number>();
|
||||
c.y = c.y;
|
||||
|
||||
class Box<T> {
|
||||
#value!: T;
|
||||
|
||||
get value() {
|
||||
return this.#value;
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
this.#value = value;
|
||||
}
|
||||
}
|
||||
|
||||
new Box<number>().value = 3;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
// @target: esnext
|
||||
// @lib: esnext
|
||||
// @declaration: true
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @filename: genericSetterInClassTypeJsDoc.js
|
||||
// @out: genericSetterInClassTypeJsDoc-out.js
|
||||
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
class Box {
|
||||
#value;
|
||||
|
||||
/** @param {T} initialValue */
|
||||
constructor(initialValue) {
|
||||
this.#value = initialValue;
|
||||
}
|
||||
|
||||
/** @type {T} */
|
||||
get value() {
|
||||
return this.#value;
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
this.#value = value;
|
||||
}
|
||||
}
|
||||
|
||||
new Box(3).value = 3;
|
||||
Loading…
x
Reference in New Issue
Block a user