From 53373abe7f99f17037fc3af690524b6afb0a3f92 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 15 Dec 2020 11:28:39 -0800 Subject: [PATCH 01/11] remove too-late fix --- .../accessorsOverrideProperty8.errors.txt | 38 ++++++++ .../reference/accessorsOverrideProperty8.js | 50 ++++++++++ .../accessorsOverrideProperty8.symbols | 92 +++++++++++++++++++ .../accessorsOverrideProperty8.types | 78 ++++++++++++++++ .../accessorsOverrideProperty8.ts | 32 +++++++ 5 files changed, 290 insertions(+) create mode 100644 tests/baselines/reference/accessorsOverrideProperty8.errors.txt create mode 100644 tests/baselines/reference/accessorsOverrideProperty8.js create mode 100644 tests/baselines/reference/accessorsOverrideProperty8.symbols create mode 100644 tests/baselines/reference/accessorsOverrideProperty8.types create mode 100644 tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts diff --git a/tests/baselines/reference/accessorsOverrideProperty8.errors.txt b/tests/baselines/reference/accessorsOverrideProperty8.errors.txt new file mode 100644 index 0000000000000..e9cffb3ee9e76 --- /dev/null +++ b/tests/baselines/reference/accessorsOverrideProperty8.errors.txt @@ -0,0 +1,38 @@ +tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts(24,9): error TS2611: 'y' is defined as a property in class 'Base & Properties<{ readonly x: "boolean"; y: "string"; }>', but is overridden here in 'MyClass' as an accessor. + + +==== tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts (1 errors) ==== + type Types = 'boolean' | 'unknown' | 'string'; + + type Properties = { + readonly [key in keyof T]: T[key] extends 'boolean' ? boolean : T[key] extends 'string' ? string : unknown + } + + type AnyCtor

= new (...a: any[]) => P + + declare function classWithProperties(properties: T, klass: AnyCtor

): { + new(): P & Properties; + prototype: P & Properties + }; + + const Base = classWithProperties({ + get x() { return 'boolean' as const }, + y: 'string', + }, class Base { + }); + + class MyClass extends Base { + get x() { + return false; + } + get y() { + ~ +!!! error TS2611: 'y' is defined as a property in class 'Base & Properties<{ readonly x: "boolean"; y: "string"; }>', but is overridden here in 'MyClass' as an accessor. + return 'hi' + } + } + + const mine = new MyClass(); + const value = mine.x; + + \ No newline at end of file diff --git a/tests/baselines/reference/accessorsOverrideProperty8.js b/tests/baselines/reference/accessorsOverrideProperty8.js new file mode 100644 index 0000000000000..bd51c4b9afbaa --- /dev/null +++ b/tests/baselines/reference/accessorsOverrideProperty8.js @@ -0,0 +1,50 @@ +//// [accessorsOverrideProperty8.ts] +type Types = 'boolean' | 'unknown' | 'string'; + +type Properties = { + readonly [key in keyof T]: T[key] extends 'boolean' ? boolean : T[key] extends 'string' ? string : unknown +} + +type AnyCtor

= new (...a: any[]) => P + +declare function classWithProperties(properties: T, klass: AnyCtor

): { + new(): P & Properties; + prototype: P & Properties +}; + +const Base = classWithProperties({ + get x() { return 'boolean' as const }, + y: 'string', +}, class Base { +}); + +class MyClass extends Base { + get x() { + return false; + } + get y() { + return 'hi' + } +} + +const mine = new MyClass(); +const value = mine.x; + + + +//// [accessorsOverrideProperty8.js] +const Base = classWithProperties({ + get x() { return 'boolean'; }, + y: 'string', +}, class Base { +}); +class MyClass extends Base { + get x() { + return false; + } + get y() { + return 'hi'; + } +} +const mine = new MyClass(); +const value = mine.x; diff --git a/tests/baselines/reference/accessorsOverrideProperty8.symbols b/tests/baselines/reference/accessorsOverrideProperty8.symbols new file mode 100644 index 0000000000000..05d49002ddd37 --- /dev/null +++ b/tests/baselines/reference/accessorsOverrideProperty8.symbols @@ -0,0 +1,92 @@ +=== tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts === +type Types = 'boolean' | 'unknown' | 'string'; +>Types : Symbol(Types, Decl(accessorsOverrideProperty8.ts, 0, 0)) + +type Properties = { +>Properties : Symbol(Properties, Decl(accessorsOverrideProperty8.ts, 0, 46)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 2, 16)) +>key : Symbol(key, Decl(accessorsOverrideProperty8.ts, 2, 29)) +>Types : Symbol(Types, Decl(accessorsOverrideProperty8.ts, 0, 0)) + + readonly [key in keyof T]: T[key] extends 'boolean' ? boolean : T[key] extends 'string' ? string : unknown +>key : Symbol(key, Decl(accessorsOverrideProperty8.ts, 3, 14)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 2, 16)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 2, 16)) +>key : Symbol(key, Decl(accessorsOverrideProperty8.ts, 3, 14)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 2, 16)) +>key : Symbol(key, Decl(accessorsOverrideProperty8.ts, 3, 14)) +} + +type AnyCtor

= new (...a: any[]) => P +>AnyCtor : Symbol(AnyCtor, Decl(accessorsOverrideProperty8.ts, 4, 1)) +>P : Symbol(P, Decl(accessorsOverrideProperty8.ts, 6, 13)) +>a : Symbol(a, Decl(accessorsOverrideProperty8.ts, 6, 38)) +>P : Symbol(P, Decl(accessorsOverrideProperty8.ts, 6, 13)) + +declare function classWithProperties(properties: T, klass: AnyCtor

): { +>classWithProperties : Symbol(classWithProperties, Decl(accessorsOverrideProperty8.ts, 6, 55)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 8, 37)) +>key : Symbol(key, Decl(accessorsOverrideProperty8.ts, 8, 50)) +>Types : Symbol(Types, Decl(accessorsOverrideProperty8.ts, 0, 0)) +>P : Symbol(P, Decl(accessorsOverrideProperty8.ts, 8, 72)) +>properties : Symbol(properties, Decl(accessorsOverrideProperty8.ts, 8, 91)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 8, 37)) +>klass : Symbol(klass, Decl(accessorsOverrideProperty8.ts, 8, 105)) +>AnyCtor : Symbol(AnyCtor, Decl(accessorsOverrideProperty8.ts, 4, 1)) +>P : Symbol(P, Decl(accessorsOverrideProperty8.ts, 8, 72)) + + new(): P & Properties; +>P : Symbol(P, Decl(accessorsOverrideProperty8.ts, 8, 72)) +>Properties : Symbol(Properties, Decl(accessorsOverrideProperty8.ts, 0, 46)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 8, 37)) + + prototype: P & Properties +>prototype : Symbol(prototype, Decl(accessorsOverrideProperty8.ts, 9, 29)) +>P : Symbol(P, Decl(accessorsOverrideProperty8.ts, 8, 72)) +>Properties : Symbol(Properties, Decl(accessorsOverrideProperty8.ts, 0, 46)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 8, 37)) + +}; + +const Base = classWithProperties({ +>Base : Symbol(Base, Decl(accessorsOverrideProperty8.ts, 13, 5)) +>classWithProperties : Symbol(classWithProperties, Decl(accessorsOverrideProperty8.ts, 6, 55)) + + get x() { return 'boolean' as const }, +>x : Symbol(x, Decl(accessorsOverrideProperty8.ts, 13, 34)) + + y: 'string', +>y : Symbol(y, Decl(accessorsOverrideProperty8.ts, 14, 42)) + +}, class Base { +>Base : Symbol(Base, Decl(accessorsOverrideProperty8.ts, 16, 2)) + +}); + +class MyClass extends Base { +>MyClass : Symbol(MyClass, Decl(accessorsOverrideProperty8.ts, 17, 3)) +>Base : Symbol(Base, Decl(accessorsOverrideProperty8.ts, 13, 5)) + + get x() { +>x : Symbol(MyClass.x, Decl(accessorsOverrideProperty8.ts, 19, 28)) + + return false; + } + get y() { +>y : Symbol(MyClass.y, Decl(accessorsOverrideProperty8.ts, 22, 5)) + + return 'hi' + } +} + +const mine = new MyClass(); +>mine : Symbol(mine, Decl(accessorsOverrideProperty8.ts, 28, 5)) +>MyClass : Symbol(MyClass, Decl(accessorsOverrideProperty8.ts, 17, 3)) + +const value = mine.x; +>value : Symbol(value, Decl(accessorsOverrideProperty8.ts, 29, 5)) +>mine.x : Symbol(MyClass.x, Decl(accessorsOverrideProperty8.ts, 19, 28)) +>mine : Symbol(mine, Decl(accessorsOverrideProperty8.ts, 28, 5)) +>x : Symbol(MyClass.x, Decl(accessorsOverrideProperty8.ts, 19, 28)) + + diff --git a/tests/baselines/reference/accessorsOverrideProperty8.types b/tests/baselines/reference/accessorsOverrideProperty8.types new file mode 100644 index 0000000000000..2677779ec951b --- /dev/null +++ b/tests/baselines/reference/accessorsOverrideProperty8.types @@ -0,0 +1,78 @@ +=== tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts === +type Types = 'boolean' | 'unknown' | 'string'; +>Types : Types + +type Properties = { +>Properties : Properties +>key : string + + readonly [key in keyof T]: T[key] extends 'boolean' ? boolean : T[key] extends 'string' ? string : unknown +} + +type AnyCtor

= new (...a: any[]) => P +>AnyCtor : AnyCtor

+>a : any[] + +declare function classWithProperties(properties: T, klass: AnyCtor

): { +>classWithProperties : (properties: T, klass: AnyCtor

) => { new (): P & Properties; prototype: P & Properties;} +>key : string +>properties : T +>klass : AnyCtor

+ + new(): P & Properties; + prototype: P & Properties +>prototype : P & Properties + +}; + +const Base = classWithProperties({ +>Base : { new (): Base & Properties<{ readonly x: "boolean"; y: "string"; }>; prototype: Base & Properties<{ readonly x: "boolean"; y: "string"; }>; } +>classWithProperties({ get x() { return 'boolean' as const }, y: 'string',}, class Base {}) : { new (): Base & Properties<{ readonly x: "boolean"; y: "string"; }>; prototype: Base & Properties<{ readonly x: "boolean"; y: "string"; }>; } +>classWithProperties : (properties: T, klass: AnyCtor

) => { new (): P & Properties; prototype: P & Properties; } +>{ get x() { return 'boolean' as const }, y: 'string',} : { readonly x: "boolean"; y: "string"; } + + get x() { return 'boolean' as const }, +>x : "boolean" +>'boolean' as const : "boolean" +>'boolean' : "boolean" + + y: 'string', +>y : "string" +>'string' : "string" + +}, class Base { +>class Base {} : typeof Base +>Base : typeof Base + +}); + +class MyClass extends Base { +>MyClass : MyClass +>Base : Base & Properties<{ readonly x: "boolean"; y: "string"; }> + + get x() { +>x : boolean + + return false; +>false : false + } + get y() { +>y : string + + return 'hi' +>'hi' : "hi" + } +} + +const mine = new MyClass(); +>mine : MyClass +>new MyClass() : MyClass +>MyClass : typeof MyClass + +const value = mine.x; +>value : boolean +>mine.x : boolean +>mine : MyClass +>x : boolean + + diff --git a/tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts b/tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts new file mode 100644 index 0000000000000..c8b02945cad08 --- /dev/null +++ b/tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts @@ -0,0 +1,32 @@ +// @target: es2019 +type Types = 'boolean' | 'unknown' | 'string'; + +type Properties = { + readonly [key in keyof T]: T[key] extends 'boolean' ? boolean : T[key] extends 'string' ? string : unknown +} + +type AnyCtor

= new (...a: any[]) => P + +declare function classWithProperties(properties: T, klass: AnyCtor

): { + new(): P & Properties; + prototype: P & Properties +}; + +const Base = classWithProperties({ + get x() { return 'boolean' as const }, + y: 'string', +}, class Base { +}); + +class MyClass extends Base { + get x() { + return false; + } + get y() { + return 'hi' + } +} + +const mine = new MyClass(); +const value = mine.x; + From e638d6bf2f2bc278264a2ebf84aa88b92924418a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Wed, 16 Dec 2020 09:21:00 -0800 Subject: [PATCH 02/11] Allow any property from a mapped type --- src/compiler/checker.ts | 3 +- .../accessorsOverrideProperty8.errors.txt | 38 ------------------- 2 files changed, 2 insertions(+), 39 deletions(-) delete mode 100644 tests/baselines/reference/accessorsOverrideProperty8.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9283458cb67a7..e6fad542bc014 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -35770,8 +35770,9 @@ namespace ts { // property/accessor is overridden with property/accessor if (baseDeclarationFlags & ModifierFlags.Abstract && !(base.valueDeclaration && isPropertyDeclaration(base.valueDeclaration) && base.valueDeclaration.initializer) || base.valueDeclaration && base.valueDeclaration.parent.kind === SyntaxKind.InterfaceDeclaration + || getCheckFlags(base) & CheckFlags.Mapped || derived.valueDeclaration && isBinaryExpression(derived.valueDeclaration)) { - // when the base property is abstract or from an interface, base/derived flags don't need to match + // when the base property is abstract or from an interface or mapped type, base/derived flags don't need to match // same when the derived property is from an assignment continue; } diff --git a/tests/baselines/reference/accessorsOverrideProperty8.errors.txt b/tests/baselines/reference/accessorsOverrideProperty8.errors.txt deleted file mode 100644 index e9cffb3ee9e76..0000000000000 --- a/tests/baselines/reference/accessorsOverrideProperty8.errors.txt +++ /dev/null @@ -1,38 +0,0 @@ -tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts(24,9): error TS2611: 'y' is defined as a property in class 'Base & Properties<{ readonly x: "boolean"; y: "string"; }>', but is overridden here in 'MyClass' as an accessor. - - -==== tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts (1 errors) ==== - type Types = 'boolean' | 'unknown' | 'string'; - - type Properties = { - readonly [key in keyof T]: T[key] extends 'boolean' ? boolean : T[key] extends 'string' ? string : unknown - } - - type AnyCtor

= new (...a: any[]) => P - - declare function classWithProperties(properties: T, klass: AnyCtor

): { - new(): P & Properties; - prototype: P & Properties - }; - - const Base = classWithProperties({ - get x() { return 'boolean' as const }, - y: 'string', - }, class Base { - }); - - class MyClass extends Base { - get x() { - return false; - } - get y() { - ~ -!!! error TS2611: 'y' is defined as a property in class 'Base & Properties<{ readonly x: "boolean"; y: "string"; }>', but is overridden here in 'MyClass' as an accessor. - return 'hi' - } - } - - const mine = new MyClass(); - const value = mine.x; - - \ No newline at end of file From 63fd359ffd42687a87ff8c929efeba9fd222c01c Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 9 Feb 2021 14:49:03 -0800 Subject: [PATCH 03/11] turn off error for any non-class base --- src/compiler/checker.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 38e72fca34871..e4c2b0297879a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -36226,10 +36226,9 @@ namespace ts { if (basePropertyFlags && derivedPropertyFlags) { // property/accessor is overridden with property/accessor if (baseDeclarationFlags & ModifierFlags.Abstract && !(base.valueDeclaration && isPropertyDeclaration(base.valueDeclaration) && base.valueDeclaration.initializer) - || base.valueDeclaration && base.valueDeclaration.parent.kind === SyntaxKind.InterfaceDeclaration - || getCheckFlags(base) & CheckFlags.Mapped + || !base.declarations?.some(decl => isClassLike(decl.parent)) || derived.valueDeclaration && isBinaryExpression(derived.valueDeclaration)) { - // when the base property is abstract or from an interface or mapped type, base/derived flags don't need to match + // when the base property is abstract or not from a class, base/derived flags don't need to match // same when the derived property is from an assignment continue; } From 80112a89b7803a79edbbdfd1c3a5d0e177547c71 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 9 Feb 2021 16:53:58 -0800 Subject: [PATCH 04/11] Also handle synthetic properties more laxly Originally from #42635, but this version is simpler. --- src/compiler/checker.ts | 15 ++- .../reference/accessorsOverrideProperty9.js | 79 +++++++++++++ .../accessorsOverrideProperty9.symbols | 111 ++++++++++++++++++ .../accessorsOverrideProperty9.types | 89 ++++++++++++++ .../accessorsOverrideProperty9.ts | 49 ++++++++ 5 files changed, 339 insertions(+), 4 deletions(-) create mode 100644 tests/baselines/reference/accessorsOverrideProperty9.js create mode 100644 tests/baselines/reference/accessorsOverrideProperty9.symbols create mode 100644 tests/baselines/reference/accessorsOverrideProperty9.types create mode 100644 tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty9.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e4c2b0297879a..c341028ad898f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6899,7 +6899,7 @@ namespace ts { ...!length(baseTypes) ? [] : [factory.createHeritageClause(SyntaxKind.ExtendsKeyword, map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)))], ...!length(implementsExpressions) ? [] : [factory.createHeritageClause(SyntaxKind.ImplementsKeyword, implementsExpressions)] ]; - const symbolProps = getNonInterhitedProperties(classType, baseTypes, getPropertiesOfType(classType)); + const symbolProps = getNonInheritedProperties(classType, baseTypes, getPropertiesOfType(classType)); const publicSymbolProps = filter(symbolProps, s => { // `valueDeclaration` could be undefined if inherited from // a union/intersection base type, but inherited properties @@ -36225,10 +36225,12 @@ namespace ts { const derivedPropertyFlags = derived.flags & SymbolFlags.PropertyOrAccessor; if (basePropertyFlags && derivedPropertyFlags) { // property/accessor is overridden with property/accessor - if (baseDeclarationFlags & ModifierFlags.Abstract && !(base.valueDeclaration && isPropertyDeclaration(base.valueDeclaration) && base.valueDeclaration.initializer) - || !base.declarations?.some(decl => isClassLike(decl.parent)) + if ((getCheckFlags(base) & CheckFlags.Synthetic + ? base.declarations?.some(d => isPropertyAbstractOrNonClass(d, baseDeclarationFlags)) + : base.declarations?.every(d => isPropertyAbstractOrNonClass(d, baseDeclarationFlags))) || derived.valueDeclaration && isBinaryExpression(derived.valueDeclaration)) { // when the base property is abstract or not from a class, base/derived flags don't need to match + // for intersection properties, this must be true of *any* of the declarations, for others it must be true of *all* // same when the derived property is from an assignment continue; } @@ -36286,7 +36288,12 @@ namespace ts { } } - function getNonInterhitedProperties(type: InterfaceType, baseTypes: BaseType[], properties: Symbol[]) { + function isPropertyAbstractOrNonClass(declaration: Declaration, baseDeclarationFlags: ModifierFlags) { + return baseDeclarationFlags & ModifierFlags.Abstract && (!isPropertyDeclaration(declaration) || !declaration.initializer) + || !isClassLike(declaration.parent); + } + + function getNonInheritedProperties(type: InterfaceType, baseTypes: BaseType[], properties: Symbol[]) { if (!length(baseTypes)) { return properties; } diff --git a/tests/baselines/reference/accessorsOverrideProperty9.js b/tests/baselines/reference/accessorsOverrideProperty9.js new file mode 100644 index 0000000000000..a1b8d7bde87aa --- /dev/null +++ b/tests/baselines/reference/accessorsOverrideProperty9.js @@ -0,0 +1,79 @@ +//// [accessorsOverrideProperty9.ts] +// #41347, based on microsoft/rushstack + +// Mixin utilities +export type Constructor = new (...args: any[]) => T; +export type PropertiesOf = { [K in keyof T]: T[K] }; + +interface IApiItemConstructor extends Constructor, PropertiesOf {} + +// Base class +class ApiItem { + public get members(): ReadonlyArray { + return []; + } +} + +// Normal subclass +class ApiEnumMember extends ApiItem { +} + +// Mixin base class +interface ApiItemContainerMixin extends ApiItem { + readonly members: ReadonlyArray; +} + +function ApiItemContainerMixin( + baseClass: TBaseClass +): TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) { + abstract class MixedClass extends baseClass implements ApiItemContainerMixin { + public constructor(...args: any[]) { + super(...args); + } + + public get members(): ReadonlyArray { + return []; + } + } + + return MixedClass; +} + +// Subclass inheriting from mixin +export class ApiEnum extends ApiItemContainerMixin(ApiItem) { + // This worked prior to TypeScript 4.0: + public get members(): ReadonlyArray { + return []; + } +} + + +//// [accessorsOverrideProperty9.js] +// #41347, based on microsoft/rushstack +// Base class +class ApiItem { + get members() { + return []; + } +} +// Normal subclass +class ApiEnumMember extends ApiItem { +} +function ApiItemContainerMixin(baseClass) { + class MixedClass extends baseClass { + constructor(...args) { + super(...args); + } + get members() { + return []; + } + } + return MixedClass; +} +// Subclass inheriting from mixin +export class ApiEnum extends ApiItemContainerMixin(ApiItem) { + // This worked prior to TypeScript 4.0: + get members() { + return []; + } +} diff --git a/tests/baselines/reference/accessorsOverrideProperty9.symbols b/tests/baselines/reference/accessorsOverrideProperty9.symbols new file mode 100644 index 0000000000000..5195876798a4f --- /dev/null +++ b/tests/baselines/reference/accessorsOverrideProperty9.symbols @@ -0,0 +1,111 @@ +=== tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty9.ts === +// #41347, based on microsoft/rushstack + +// Mixin utilities +export type Constructor = new (...args: any[]) => T; +>Constructor : Symbol(Constructor, Decl(accessorsOverrideProperty9.ts, 0, 0)) +>T : Symbol(T, Decl(accessorsOverrideProperty9.ts, 3, 24)) +>args : Symbol(args, Decl(accessorsOverrideProperty9.ts, 3, 39)) +>T : Symbol(T, Decl(accessorsOverrideProperty9.ts, 3, 24)) + +export type PropertiesOf = { [K in keyof T]: T[K] }; +>PropertiesOf : Symbol(PropertiesOf, Decl(accessorsOverrideProperty9.ts, 3, 60)) +>T : Symbol(T, Decl(accessorsOverrideProperty9.ts, 4, 25)) +>K : Symbol(K, Decl(accessorsOverrideProperty9.ts, 4, 33)) +>T : Symbol(T, Decl(accessorsOverrideProperty9.ts, 4, 25)) +>T : Symbol(T, Decl(accessorsOverrideProperty9.ts, 4, 25)) +>K : Symbol(K, Decl(accessorsOverrideProperty9.ts, 4, 33)) + +interface IApiItemConstructor extends Constructor, PropertiesOf {} +>IApiItemConstructor : Symbol(IApiItemConstructor, Decl(accessorsOverrideProperty9.ts, 4, 55)) +>Constructor : Symbol(Constructor, Decl(accessorsOverrideProperty9.ts, 0, 0)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) +>PropertiesOf : Symbol(PropertiesOf, Decl(accessorsOverrideProperty9.ts, 3, 60)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) + +// Base class +class ApiItem { +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) + + public get members(): ReadonlyArray { +>members : Symbol(ApiItem.members, Decl(accessorsOverrideProperty9.ts, 9, 15)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) + + return []; + } +} + +// Normal subclass +class ApiEnumMember extends ApiItem { +>ApiEnumMember : Symbol(ApiEnumMember, Decl(accessorsOverrideProperty9.ts, 13, 1)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) +} + +// Mixin base class +interface ApiItemContainerMixin extends ApiItem { +>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty9.ts, 22, 1), Decl(accessorsOverrideProperty9.ts, 17, 1)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) + + readonly members: ReadonlyArray; +>members : Symbol(ApiItemContainerMixin.members, Decl(accessorsOverrideProperty9.ts, 20, 49)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) +} + +function ApiItemContainerMixin( +>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty9.ts, 22, 1), Decl(accessorsOverrideProperty9.ts, 17, 1)) +>TBaseClass : Symbol(TBaseClass, Decl(accessorsOverrideProperty9.ts, 24, 31)) +>IApiItemConstructor : Symbol(IApiItemConstructor, Decl(accessorsOverrideProperty9.ts, 4, 55)) + + baseClass: TBaseClass +>baseClass : Symbol(baseClass, Decl(accessorsOverrideProperty9.ts, 24, 71)) +>TBaseClass : Symbol(TBaseClass, Decl(accessorsOverrideProperty9.ts, 24, 31)) + +): TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) { +>TBaseClass : Symbol(TBaseClass, Decl(accessorsOverrideProperty9.ts, 24, 31)) +>args : Symbol(args, Decl(accessorsOverrideProperty9.ts, 26, 22)) +>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty9.ts, 22, 1), Decl(accessorsOverrideProperty9.ts, 17, 1)) + + abstract class MixedClass extends baseClass implements ApiItemContainerMixin { +>MixedClass : Symbol(MixedClass, Decl(accessorsOverrideProperty9.ts, 26, 65)) +>baseClass : Symbol(baseClass, Decl(accessorsOverrideProperty9.ts, 24, 71)) +>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty9.ts, 22, 1), Decl(accessorsOverrideProperty9.ts, 17, 1)) + + public constructor(...args: any[]) { +>args : Symbol(args, Decl(accessorsOverrideProperty9.ts, 28, 23)) + + super(...args); +>super : Symbol(TBaseClass, Decl(accessorsOverrideProperty9.ts, 24, 31)) +>args : Symbol(args, Decl(accessorsOverrideProperty9.ts, 28, 23)) + } + + public get members(): ReadonlyArray { +>members : Symbol(MixedClass.members, Decl(accessorsOverrideProperty9.ts, 30, 5)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) + + return []; + } + } + + return MixedClass; +>MixedClass : Symbol(MixedClass, Decl(accessorsOverrideProperty9.ts, 26, 65)) +} + +// Subclass inheriting from mixin +export class ApiEnum extends ApiItemContainerMixin(ApiItem) { +>ApiEnum : Symbol(ApiEnum, Decl(accessorsOverrideProperty9.ts, 38, 1)) +>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty9.ts, 22, 1), Decl(accessorsOverrideProperty9.ts, 17, 1)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) + + // This worked prior to TypeScript 4.0: + public get members(): ReadonlyArray { +>members : Symbol(ApiEnum.members, Decl(accessorsOverrideProperty9.ts, 41, 61)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --)) +>ApiEnumMember : Symbol(ApiEnumMember, Decl(accessorsOverrideProperty9.ts, 13, 1)) + + return []; + } +} + diff --git a/tests/baselines/reference/accessorsOverrideProperty9.types b/tests/baselines/reference/accessorsOverrideProperty9.types new file mode 100644 index 0000000000000..dcbc3523e10cd --- /dev/null +++ b/tests/baselines/reference/accessorsOverrideProperty9.types @@ -0,0 +1,89 @@ +=== tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty9.ts === +// #41347, based on microsoft/rushstack + +// Mixin utilities +export type Constructor = new (...args: any[]) => T; +>Constructor : Constructor +>args : any[] + +export type PropertiesOf = { [K in keyof T]: T[K] }; +>PropertiesOf : PropertiesOf + +interface IApiItemConstructor extends Constructor, PropertiesOf {} +>ApiItem : typeof ApiItem + +// Base class +class ApiItem { +>ApiItem : ApiItem + + public get members(): ReadonlyArray { +>members : readonly ApiItem[] + + return []; +>[] : never[] + } +} + +// Normal subclass +class ApiEnumMember extends ApiItem { +>ApiEnumMember : ApiEnumMember +>ApiItem : ApiItem +} + +// Mixin base class +interface ApiItemContainerMixin extends ApiItem { + readonly members: ReadonlyArray; +>members : readonly ApiItem[] +} + +function ApiItemContainerMixin( +>ApiItemContainerMixin : (baseClass: TBaseClass) => TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) + + baseClass: TBaseClass +>baseClass : TBaseClass + +): TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) { +>args : any[] + + abstract class MixedClass extends baseClass implements ApiItemContainerMixin { +>MixedClass : MixedClass +>baseClass : ApiItem + + public constructor(...args: any[]) { +>args : any[] + + super(...args); +>super(...args) : void +>super : TBaseClass +>...args : any +>args : any[] + } + + public get members(): ReadonlyArray { +>members : readonly ApiItem[] + + return []; +>[] : never[] + } + } + + return MixedClass; +>MixedClass : ((abstract new (...args: any[]) => MixedClass) & { prototype: ApiItemContainerMixin.MixedClass; }) & TBaseClass +} + +// Subclass inheriting from mixin +export class ApiEnum extends ApiItemContainerMixin(ApiItem) { +>ApiEnum : ApiEnum +>ApiItemContainerMixin(ApiItem) : ApiItem & ApiItemContainerMixin +>ApiItemContainerMixin : (baseClass: TBaseClass) => TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) +>ApiItem : typeof ApiItem + + // This worked prior to TypeScript 4.0: + public get members(): ReadonlyArray { +>members : readonly ApiEnumMember[] + + return []; +>[] : never[] + } +} + diff --git a/tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty9.ts b/tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty9.ts new file mode 100644 index 0000000000000..9dfa1a833b0c8 --- /dev/null +++ b/tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty9.ts @@ -0,0 +1,49 @@ +// @strict: true +// @target: es2017 +// #41347, based on microsoft/rushstack + +// Mixin utilities +export type Constructor = new (...args: any[]) => T; +export type PropertiesOf = { [K in keyof T]: T[K] }; + +interface IApiItemConstructor extends Constructor, PropertiesOf {} + +// Base class +class ApiItem { + public get members(): ReadonlyArray { + return []; + } +} + +// Normal subclass +class ApiEnumMember extends ApiItem { +} + +// Mixin base class +interface ApiItemContainerMixin extends ApiItem { + readonly members: ReadonlyArray; +} + +function ApiItemContainerMixin( + baseClass: TBaseClass +): TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) { + abstract class MixedClass extends baseClass implements ApiItemContainerMixin { + public constructor(...args: any[]) { + super(...args); + } + + public get members(): ReadonlyArray { + return []; + } + } + + return MixedClass; +} + +// Subclass inheriting from mixin +export class ApiEnum extends ApiItemContainerMixin(ApiItem) { + // This worked prior to TypeScript 4.0: + public get members(): ReadonlyArray { + return []; + } +} From f70a4487edaec5a7e3f0aca2f22cadd85da274cb Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 3 Feb 2022 16:46:39 -0800 Subject: [PATCH 05/11] update baselines --- tests/baselines/reference/accessorsOverrideProperty8.symbols | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/baselines/reference/accessorsOverrideProperty8.symbols b/tests/baselines/reference/accessorsOverrideProperty8.symbols index 05d49002ddd37..7e60b8c582de5 100644 --- a/tests/baselines/reference/accessorsOverrideProperty8.symbols +++ b/tests/baselines/reference/accessorsOverrideProperty8.symbols @@ -54,6 +54,7 @@ const Base = classWithProperties({ get x() { return 'boolean' as const }, >x : Symbol(x, Decl(accessorsOverrideProperty8.ts, 13, 34)) +>const : Symbol(const) y: 'string', >y : Symbol(y, Decl(accessorsOverrideProperty8.ts, 14, 42)) From 0528e7358285d03d7215342834baf50e5dab43bd Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 16 May 2022 15:54:52 -0700 Subject: [PATCH 06/11] Update baselines --- tests/baselines/reference/accessorsOverrideProperty8.types | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/baselines/reference/accessorsOverrideProperty8.types b/tests/baselines/reference/accessorsOverrideProperty8.types index 2677779ec951b..1379593d280a4 100644 --- a/tests/baselines/reference/accessorsOverrideProperty8.types +++ b/tests/baselines/reference/accessorsOverrideProperty8.types @@ -1,6 +1,6 @@ === tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts === type Types = 'boolean' | 'unknown' | 'string'; ->Types : Types +>Types : "string" | "boolean" | "unknown" type Properties = { >Properties : Properties From fee6a0e16f8cd4bfd8c2f6dab987ebd7792a83ac Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 17 May 2022 15:22:33 -0700 Subject: [PATCH 07/11] createUnionProperty of accessors creates an accessor Seems simple and doesn't break much. I need to double-check the few test failures, however. --- src/compiler/checker.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7af9a0bf0f294..0c1ed31771309 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12449,7 +12449,11 @@ namespace ts { propTypes.push(type); } addRange(propTypes, indexTypes); - const result = createSymbol(SymbolFlags.Property | optionalFlag, name, syntheticFlag | checkFlags); + const oopsAllAccessors = + (props.every(p => p.flags & SymbolFlags.GetAccessor) ? SymbolFlags.GetAccessor : 0) + | (props.every(p => p.flags & SymbolFlags.SetAccessor) ? SymbolFlags.SetAccessor : 0) + | (props.every(p => !(p.flags & SymbolFlags.Accessor)) ? SymbolFlags.Property : 0); + const result = createSymbol(oopsAllAccessors | optionalFlag, name, syntheticFlag | checkFlags); result.containingType = containingType; if (!hasNonUniformValueDeclaration && firstValueDeclaration) { result.valueDeclaration = firstValueDeclaration; @@ -39950,10 +39954,11 @@ namespace ts { if (basePropertyFlags && derivedPropertyFlags) { // property/accessor is overridden with property/accessor if ((getCheckFlags(base) & CheckFlags.Synthetic - ? base.declarations?.some(d => isPropertyAbstractOrNonClass(d, baseDeclarationFlags)) - : base.declarations?.every(d => isPropertyAbstractOrNonClass(d, baseDeclarationFlags))) + ? base.declarations?.some(d => isPropertyAbstract(d, baseDeclarationFlags)) + : base.declarations?.every(d => isPropertyAbstract(d, baseDeclarationFlags))) + || getCheckFlags(base) & CheckFlags.Mapped || derived.valueDeclaration && isBinaryExpression(derived.valueDeclaration)) { - // when the base property is abstract or not from a class, base/derived flags don't need to match + // when the base property is abstract, base/derived flags don't need to match // for intersection properties, this must be true of *any* of the declarations, for others it must be true of *all* // same when the derived property is from an assignment continue; @@ -40012,9 +40017,9 @@ namespace ts { } } - function isPropertyAbstractOrNonClass(declaration: Declaration, baseDeclarationFlags: ModifierFlags) { + function isPropertyAbstract(declaration: Declaration, baseDeclarationFlags: ModifierFlags) { return baseDeclarationFlags & ModifierFlags.Abstract && (!isPropertyDeclaration(declaration) || !declaration.initializer) - || !isClassLike(declaration.parent); + || isInterfaceDeclaration(declaration.parent); } function getNonInheritedProperties(type: InterfaceType, baseTypes: BaseType[], properties: Symbol[]) { From 0eac002bcc68a0d48d168de7116365d9a36789ba Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 24 May 2022 13:53:21 -0700 Subject: [PATCH 08/11] Fix computation of write type of accessors --- src/compiler/checker.ts | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a107bf616e611..81ca4ed6d10ce 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9915,9 +9915,9 @@ namespace ts { getTypeOfSymbol(symbol); } if (symbol.flags & SymbolFlags.Accessor) { - return checkFlags & CheckFlags.Instantiated ? - getWriteTypeOfInstantiatedSymbol(symbol) : - getWriteTypeOfAccessors(symbol); + return checkFlags & CheckFlags.DeferredType ? getWriteTypeOfSymbolWithDeferredType(symbol) || getTypeOfSymbolWithDeferredType(symbol) + : checkFlags & CheckFlags.Instantiated ? getWriteTypeOfInstantiatedSymbol(symbol) + : getWriteTypeOfAccessors(symbol); } return getTypeOfSymbol(symbol); } @@ -12449,11 +12449,16 @@ namespace ts { propTypes.push(type); } addRange(propTypes, indexTypes); - const oopsAllAccessors = - (props.every(p => p.flags & SymbolFlags.GetAccessor) ? SymbolFlags.GetAccessor : 0) - | (props.every(p => p.flags & SymbolFlags.SetAccessor) ? SymbolFlags.SetAccessor : 0) - | (props.every(p => !(p.flags & SymbolFlags.Accessor)) ? SymbolFlags.Property : 0); - const result = createSymbol(oopsAllAccessors | optionalFlag, name, syntheticFlag | checkFlags); + let propertyFlag: number = 0; + if (props.every(p => p.flags & SymbolFlags.Accessor)) { // TODO: Move this into the `const prop of props` loop + const f = isUnion ? props.every : props.some; + propertyFlag = (f.call(props, (p : Symbol) => p.flags & SymbolFlags.GetAccessor) ? SymbolFlags.GetAccessor : 0) + | (f.call(props, (p : Symbol) => p.flags & SymbolFlags.SetAccessor) ? SymbolFlags.SetAccessor : 0); + } + if (propertyFlag === 0) { + propertyFlag = SymbolFlags.Property; + } + const result = createSymbol(propertyFlag | optionalFlag, name, syntheticFlag | checkFlags); result.containingType = containingType; if (!hasNonUniformValueDeclaration && firstValueDeclaration) { result.valueDeclaration = firstValueDeclaration; @@ -39954,11 +39959,11 @@ namespace ts { if (basePropertyFlags && derivedPropertyFlags) { // property/accessor is overridden with property/accessor if ((getCheckFlags(base) & CheckFlags.Synthetic - ? base.declarations?.some(d => isPropertyAbstract(d, baseDeclarationFlags)) - : base.declarations?.every(d => isPropertyAbstract(d, baseDeclarationFlags))) + ? base.declarations?.some(d => isPropertyAbstractOrInterface(d, baseDeclarationFlags)) + : base.declarations?.every(d => isPropertyAbstractOrInterface(d, baseDeclarationFlags))) || getCheckFlags(base) & CheckFlags.Mapped || derived.valueDeclaration && isBinaryExpression(derived.valueDeclaration)) { - // when the base property is abstract, base/derived flags don't need to match + // when the base property is abstract or from an interface, base/derived flags don't need to match // for intersection properties, this must be true of *any* of the declarations, for others it must be true of *all* // same when the derived property is from an assignment continue; @@ -40017,7 +40022,7 @@ namespace ts { } } - function isPropertyAbstract(declaration: Declaration, baseDeclarationFlags: ModifierFlags) { + function isPropertyAbstractOrInterface(declaration: Declaration, baseDeclarationFlags: ModifierFlags) { return baseDeclarationFlags & ModifierFlags.Abstract && (!isPropertyDeclaration(declaration) || !declaration.initializer) || isInterfaceDeclaration(declaration.parent); } From 341229c263257a3ace87542a363133e19ee4a2f7 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 24 May 2022 16:56:07 -0700 Subject: [PATCH 09/11] Calculate property-vs-accessor in existing loop Instead of looping over the props list 3 more times. --- src/compiler/checker.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 81ca4ed6d10ce..5b68af3ffa92e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12420,6 +12420,8 @@ namespace ts { let writeTypes: Type[] | undefined; let firstValueDeclaration: Declaration | undefined; let hasNonUniformValueDeclaration = false; + let propertyFlag = 0; + let isAllAccessors = true; for (const prop of props) { if (!firstValueDeclaration) { firstValueDeclaration = prop.valueDeclaration; @@ -12447,14 +12449,16 @@ namespace ts { checkFlags |= CheckFlags.HasNeverType; } propTypes.push(type); + if (isAllAccessors && prop.flags & SymbolFlags.Accessor) { + propertyFlag = isUnion ? propertyFlag & (prop.flags & SymbolFlags.Accessor) + : propertyFlag | (prop.flags & SymbolFlags.Accessor); + } + else { + isAllAccessors = false; + propertyFlag = 0; + } } addRange(propTypes, indexTypes); - let propertyFlag: number = 0; - if (props.every(p => p.flags & SymbolFlags.Accessor)) { // TODO: Move this into the `const prop of props` loop - const f = isUnion ? props.every : props.some; - propertyFlag = (f.call(props, (p : Symbol) => p.flags & SymbolFlags.GetAccessor) ? SymbolFlags.GetAccessor : 0) - | (f.call(props, (p : Symbol) => p.flags & SymbolFlags.SetAccessor) ? SymbolFlags.SetAccessor : 0); - } if (propertyFlag === 0) { propertyFlag = SymbolFlags.Property; } From 632853bbde3a87a01e7780d809f216c63ed2d578 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Wed, 25 May 2022 16:38:19 -0700 Subject: [PATCH 10/11] Undo synthetic accessor change --- src/compiler/checker.ts | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5b68af3ffa92e..d2631cffd7bb4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9915,8 +9915,7 @@ namespace ts { getTypeOfSymbol(symbol); } if (symbol.flags & SymbolFlags.Accessor) { - return checkFlags & CheckFlags.DeferredType ? getWriteTypeOfSymbolWithDeferredType(symbol) || getTypeOfSymbolWithDeferredType(symbol) - : checkFlags & CheckFlags.Instantiated ? getWriteTypeOfInstantiatedSymbol(symbol) + return checkFlags & CheckFlags.Instantiated ? getWriteTypeOfInstantiatedSymbol(symbol) : getWriteTypeOfAccessors(symbol); } return getTypeOfSymbol(symbol); @@ -12420,8 +12419,6 @@ namespace ts { let writeTypes: Type[] | undefined; let firstValueDeclaration: Declaration | undefined; let hasNonUniformValueDeclaration = false; - let propertyFlag = 0; - let isAllAccessors = true; for (const prop of props) { if (!firstValueDeclaration) { firstValueDeclaration = prop.valueDeclaration; @@ -12449,20 +12446,9 @@ namespace ts { checkFlags |= CheckFlags.HasNeverType; } propTypes.push(type); - if (isAllAccessors && prop.flags & SymbolFlags.Accessor) { - propertyFlag = isUnion ? propertyFlag & (prop.flags & SymbolFlags.Accessor) - : propertyFlag | (prop.flags & SymbolFlags.Accessor); - } - else { - isAllAccessors = false; - propertyFlag = 0; - } } addRange(propTypes, indexTypes); - if (propertyFlag === 0) { - propertyFlag = SymbolFlags.Property; - } - const result = createSymbol(propertyFlag | optionalFlag, name, syntheticFlag | checkFlags); + const result = createSymbol(/*propertyFlag*/ SymbolFlags.Property | optionalFlag, name, syntheticFlag | checkFlags); result.containingType = containingType; if (!hasNonUniformValueDeclaration && firstValueDeclaration) { result.valueDeclaration = firstValueDeclaration; From 6addf091dfadbba191c7bbfdc9eda2410d24b260 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 26 May 2022 08:14:54 -0700 Subject: [PATCH 11/11] Minimise diff --- src/compiler/checker.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d2631cffd7bb4..a73066db6368c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9915,8 +9915,9 @@ namespace ts { getTypeOfSymbol(symbol); } if (symbol.flags & SymbolFlags.Accessor) { - return checkFlags & CheckFlags.Instantiated ? getWriteTypeOfInstantiatedSymbol(symbol) - : getWriteTypeOfAccessors(symbol); + return checkFlags & CheckFlags.Instantiated ? + getWriteTypeOfInstantiatedSymbol(symbol) : + getWriteTypeOfAccessors(symbol); } return getTypeOfSymbol(symbol); } @@ -12448,7 +12449,7 @@ namespace ts { propTypes.push(type); } addRange(propTypes, indexTypes); - const result = createSymbol(/*propertyFlag*/ SymbolFlags.Property | optionalFlag, name, syntheticFlag | checkFlags); + const result = createSymbol(SymbolFlags.Property | optionalFlag, name, syntheticFlag | checkFlags); result.containingType = containingType; if (!hasNonUniformValueDeclaration && firstValueDeclaration) { result.valueDeclaration = firstValueDeclaration;