Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -36242,10 +36242,10 @@ 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.valueDeclaration && base.valueDeclaration.parent.kind === SyntaxKind.InterfaceDeclaration
if (base.valueDeclaration && isPropertyAbstractOrFromInterface(base.valueDeclaration, baseDeclarationFlags)
|| getCheckFlags(base) & CheckFlags.Synthetic && base.declarations.some(d => isPropertyAbstractOrFromInterface(d, baseDeclarationFlags))
|| 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, from an interface or from an intersection, base/derived flags don't need to match
// same when the derived property is from an assignment
continue;
}
Expand Down Expand Up @@ -36303,7 +36303,12 @@ namespace ts {
}
}

function getNonInterhitedProperties(type: InterfaceType, baseTypes: BaseType[], properties: Symbol[]) {
function isPropertyAbstractOrFromInterface(declaration: Declaration, baseDeclarationFlags: ModifierFlags) {
return baseDeclarationFlags & ModifierFlags.Abstract && (!isPropertyDeclaration(declaration) || !declaration.initializer)
|| declaration.parent.kind === SyntaxKind.InterfaceDeclaration;
}

function getNonInheritedProperties(type: InterfaceType, baseTypes: BaseType[], properties: Symbol[]) {
if (!length(baseTypes)) {
return properties;
}
Expand Down
79 changes: 79 additions & 0 deletions tests/baselines/reference/accessorsOverrideProperty8.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//// [accessorsOverrideProperty8.ts]
// #41347, based on microsoft/rushstack

// Mixin utilities
export type Constructor<T = {}> = new (...args: any[]) => T;
export type PropertiesOf<T> = { [K in keyof T]: T[K] };

interface IApiItemConstructor extends Constructor<ApiItem>, PropertiesOf<typeof ApiItem> {}

// Base class
class ApiItem {
public get members(): ReadonlyArray<ApiItem> {
return [];
}
}

// Normal subclass
class ApiEnumMember extends ApiItem {
}

// Mixin base class
interface ApiItemContainerMixin extends ApiItem {
readonly members: ReadonlyArray<ApiItem>;
}

function ApiItemContainerMixin<TBaseClass extends IApiItemConstructor>(
baseClass: TBaseClass
): TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) {
abstract class MixedClass extends baseClass implements ApiItemContainerMixin {
public constructor(...args: any[]) {
super(...args);
}

public get members(): ReadonlyArray<ApiItem> {
return [];
}
}

return MixedClass;
}

// Subclass inheriting from mixin
export class ApiEnum extends ApiItemContainerMixin(ApiItem) {
// This worked prior to TypeScript 4.0:
public get members(): ReadonlyArray<ApiEnumMember> {
return [];
}
}


//// [accessorsOverrideProperty8.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 [];
}
}
111 changes: 111 additions & 0 deletions tests/baselines/reference/accessorsOverrideProperty8.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
=== tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts ===
// #41347, based on microsoft/rushstack

// Mixin utilities
export type Constructor<T = {}> = new (...args: any[]) => T;
>Constructor : Symbol(Constructor, Decl(accessorsOverrideProperty8.ts, 0, 0))
>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 3, 24))
>args : Symbol(args, Decl(accessorsOverrideProperty8.ts, 3, 39))
>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 3, 24))

export type PropertiesOf<T> = { [K in keyof T]: T[K] };
>PropertiesOf : Symbol(PropertiesOf, Decl(accessorsOverrideProperty8.ts, 3, 60))
>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 4, 25))
>K : Symbol(K, Decl(accessorsOverrideProperty8.ts, 4, 33))
>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 4, 25))
>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 4, 25))
>K : Symbol(K, Decl(accessorsOverrideProperty8.ts, 4, 33))

interface IApiItemConstructor extends Constructor<ApiItem>, PropertiesOf<typeof ApiItem> {}
>IApiItemConstructor : Symbol(IApiItemConstructor, Decl(accessorsOverrideProperty8.ts, 4, 55))
>Constructor : Symbol(Constructor, Decl(accessorsOverrideProperty8.ts, 0, 0))
>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty8.ts, 6, 91))
>PropertiesOf : Symbol(PropertiesOf, Decl(accessorsOverrideProperty8.ts, 3, 60))
>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty8.ts, 6, 91))

// Base class
class ApiItem {
>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty8.ts, 6, 91))

public get members(): ReadonlyArray<ApiItem> {
>members : Symbol(ApiItem.members, Decl(accessorsOverrideProperty8.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(accessorsOverrideProperty8.ts, 6, 91))

return [];
}
}

// Normal subclass
class ApiEnumMember extends ApiItem {
>ApiEnumMember : Symbol(ApiEnumMember, Decl(accessorsOverrideProperty8.ts, 13, 1))
>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty8.ts, 6, 91))
}

// Mixin base class
interface ApiItemContainerMixin extends ApiItem {
>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty8.ts, 22, 1), Decl(accessorsOverrideProperty8.ts, 17, 1))
>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty8.ts, 6, 91))

readonly members: ReadonlyArray<ApiItem>;
>members : Symbol(ApiItemContainerMixin.members, Decl(accessorsOverrideProperty8.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(accessorsOverrideProperty8.ts, 6, 91))
}

function ApiItemContainerMixin<TBaseClass extends IApiItemConstructor>(
>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty8.ts, 22, 1), Decl(accessorsOverrideProperty8.ts, 17, 1))
>TBaseClass : Symbol(TBaseClass, Decl(accessorsOverrideProperty8.ts, 24, 31))
>IApiItemConstructor : Symbol(IApiItemConstructor, Decl(accessorsOverrideProperty8.ts, 4, 55))

baseClass: TBaseClass
>baseClass : Symbol(baseClass, Decl(accessorsOverrideProperty8.ts, 24, 71))
>TBaseClass : Symbol(TBaseClass, Decl(accessorsOverrideProperty8.ts, 24, 31))

): TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) {
>TBaseClass : Symbol(TBaseClass, Decl(accessorsOverrideProperty8.ts, 24, 31))
>args : Symbol(args, Decl(accessorsOverrideProperty8.ts, 26, 22))
>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty8.ts, 22, 1), Decl(accessorsOverrideProperty8.ts, 17, 1))

abstract class MixedClass extends baseClass implements ApiItemContainerMixin {
>MixedClass : Symbol(MixedClass, Decl(accessorsOverrideProperty8.ts, 26, 65))
>baseClass : Symbol(baseClass, Decl(accessorsOverrideProperty8.ts, 24, 71))
>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty8.ts, 22, 1), Decl(accessorsOverrideProperty8.ts, 17, 1))

public constructor(...args: any[]) {
>args : Symbol(args, Decl(accessorsOverrideProperty8.ts, 28, 23))

super(...args);
>super : Symbol(TBaseClass, Decl(accessorsOverrideProperty8.ts, 24, 31))
>args : Symbol(args, Decl(accessorsOverrideProperty8.ts, 28, 23))
}

public get members(): ReadonlyArray<ApiItem> {
>members : Symbol(MixedClass.members, Decl(accessorsOverrideProperty8.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(accessorsOverrideProperty8.ts, 6, 91))

return [];
}
}

return MixedClass;
>MixedClass : Symbol(MixedClass, Decl(accessorsOverrideProperty8.ts, 26, 65))
}

// Subclass inheriting from mixin
export class ApiEnum extends ApiItemContainerMixin(ApiItem) {
>ApiEnum : Symbol(ApiEnum, Decl(accessorsOverrideProperty8.ts, 38, 1))
>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty8.ts, 22, 1), Decl(accessorsOverrideProperty8.ts, 17, 1))
>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty8.ts, 6, 91))

// This worked prior to TypeScript 4.0:
public get members(): ReadonlyArray<ApiEnumMember> {
>members : Symbol(ApiEnum.members, Decl(accessorsOverrideProperty8.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(accessorsOverrideProperty8.ts, 13, 1))

return [];
}
}

89 changes: 89 additions & 0 deletions tests/baselines/reference/accessorsOverrideProperty8.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
=== tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts ===
// #41347, based on microsoft/rushstack

// Mixin utilities
export type Constructor<T = {}> = new (...args: any[]) => T;
>Constructor : Constructor<T>
>args : any[]

export type PropertiesOf<T> = { [K in keyof T]: T[K] };
>PropertiesOf : PropertiesOf<T>

interface IApiItemConstructor extends Constructor<ApiItem>, PropertiesOf<typeof ApiItem> {}
>ApiItem : typeof ApiItem

// Base class
class ApiItem {
>ApiItem : ApiItem

public get members(): ReadonlyArray<ApiItem> {
>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<ApiItem>;
>members : readonly ApiItem[]
}

function ApiItemContainerMixin<TBaseClass extends IApiItemConstructor>(
>ApiItemContainerMixin : <TBaseClass extends IApiItemConstructor>(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<ApiItem> {
>members : readonly ApiItem[]

return [];
>[] : never[]
}
}

return MixedClass;
>MixedClass : ((abstract new (...args: any[]) => MixedClass) & { prototype: ApiItemContainerMixin<any>.MixedClass; }) & TBaseClass
}

// Subclass inheriting from mixin
export class ApiEnum extends ApiItemContainerMixin(ApiItem) {
>ApiEnum : ApiEnum
>ApiItemContainerMixin(ApiItem) : ApiItem & ApiItemContainerMixin
>ApiItemContainerMixin : <TBaseClass extends IApiItemConstructor>(baseClass: TBaseClass) => TBaseClass & (new (...args: any[]) => ApiItemContainerMixin)
>ApiItem : typeof ApiItem

// This worked prior to TypeScript 4.0:
public get members(): ReadonlyArray<ApiEnumMember> {
>members : readonly ApiEnumMember[]

return [];
>[] : never[]
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// @strict: true
// @target: es2017
// #41347, based on microsoft/rushstack

// Mixin utilities
export type Constructor<T = {}> = new (...args: any[]) => T;
export type PropertiesOf<T> = { [K in keyof T]: T[K] };

interface IApiItemConstructor extends Constructor<ApiItem>, PropertiesOf<typeof ApiItem> {}

// Base class
class ApiItem {
public get members(): ReadonlyArray<ApiItem> {
return [];
}
}

// Normal subclass
class ApiEnumMember extends ApiItem {
}

// Mixin base class
interface ApiItemContainerMixin extends ApiItem {
readonly members: ReadonlyArray<ApiItem>;
}

function ApiItemContainerMixin<TBaseClass extends IApiItemConstructor>(
baseClass: TBaseClass
): TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) {
abstract class MixedClass extends baseClass implements ApiItemContainerMixin {
public constructor(...args: any[]) {
super(...args);
}

public get members(): ReadonlyArray<ApiItem> {
return [];
}
}

return MixedClass;
}

// Subclass inheriting from mixin
export class ApiEnum extends ApiItemContainerMixin(ApiItem) {
// This worked prior to TypeScript 4.0:
public get members(): ReadonlyArray<ApiEnumMember> {
return [];
}
}