Merge pull request #14074 from Microsoft/error-on-decl-of-extends-intersection

Error when emitting the declaration for an exported class that extends an intersection
This commit is contained in:
Nathan Shively-Sanders 2017-02-15 13:43:51 -08:00 committed by GitHub
commit 1296f240c6
15 changed files with 275 additions and 99 deletions

View file

@ -21392,6 +21392,9 @@ namespace ts {
const classType = <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(node)); const classType = <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(node));
resolveBaseTypesOfClass(classType); resolveBaseTypesOfClass(classType);
const baseType = classType.resolvedBaseTypes.length ? classType.resolvedBaseTypes[0] : unknownType; const baseType = classType.resolvedBaseTypes.length ? classType.resolvedBaseTypes[0] : unknownType;
if (!baseType.symbol) {
writer.reportIllegalExtends();
}
getSymbolDisplayBuilder().buildTypeDisplay(baseType, writer, enclosingDeclaration, flags); getSymbolDisplayBuilder().buildTypeDisplay(baseType, writer, enclosingDeclaration, flags);
} }

View file

@ -190,6 +190,7 @@ namespace ts {
const writer = <EmitTextWriterWithSymbolWriter>createTextWriter(newLine); const writer = <EmitTextWriterWithSymbolWriter>createTextWriter(newLine);
writer.trackSymbol = trackSymbol; writer.trackSymbol = trackSymbol;
writer.reportInaccessibleThisError = reportInaccessibleThisError; writer.reportInaccessibleThisError = reportInaccessibleThisError;
writer.reportIllegalExtends = reportIllegalExtends;
writer.writeKeyword = writer.write; writer.writeKeyword = writer.write;
writer.writeOperator = writer.write; writer.writeOperator = writer.write;
writer.writePunctuation = writer.write; writer.writePunctuation = writer.write;
@ -313,6 +314,14 @@ namespace ts {
recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForSymbol(symbol, meaning)); recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForSymbol(symbol, meaning));
} }
function reportIllegalExtends() {
if (errorNameNode) {
reportedDeclarationError = true;
emitterDiagnostics.add(createDiagnosticForNode(errorNameNode, Diagnostics.extends_clause_of_exported_class_0_refers_to_a_type_whose_name_cannot_be_referenced,
declarationNameToString(errorNameNode)));
}
}
function reportInaccessibleThisError() { function reportInaccessibleThisError() {
if (errorNameNode) { if (errorNameNode) {
reportedDeclarationError = true; reportedDeclarationError = true;
@ -1088,7 +1097,7 @@ namespace ts {
} }
} }
function emitHeritageClause(typeReferences: ExpressionWithTypeArguments[], isImplementsList: boolean) { function emitHeritageClause(className: Identifier, typeReferences: ExpressionWithTypeArguments[], isImplementsList: boolean) {
if (typeReferences) { if (typeReferences) {
write(isImplementsList ? " implements " : " extends "); write(isImplementsList ? " implements " : " extends ");
emitCommaList(typeReferences, emitTypeOfTypeReference); emitCommaList(typeReferences, emitTypeOfTypeReference);
@ -1103,7 +1112,9 @@ namespace ts {
} }
else { else {
writer.getSymbolAccessibilityDiagnostic = getHeritageClauseVisibilityError; writer.getSymbolAccessibilityDiagnostic = getHeritageClauseVisibilityError;
errorNameNode = className;
resolver.writeBaseConstructorTypeOfClass(<ClassLikeDeclaration>enclosingDeclaration, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue, writer); resolver.writeBaseConstructorTypeOfClass(<ClassLikeDeclaration>enclosingDeclaration, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue, writer);
errorNameNode = undefined;
} }
function getHeritageClauseVisibilityError(): SymbolAccessibilityDiagnostic { function getHeritageClauseVisibilityError(): SymbolAccessibilityDiagnostic {
@ -1113,11 +1124,11 @@ namespace ts {
// Class or Interface implemented/extended is inaccessible // Class or Interface implemented/extended is inaccessible
diagnosticMessage = isImplementsList ? diagnosticMessage = isImplementsList ?
Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 : Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 :
Diagnostics.Extends_clause_of_exported_class_0_has_or_is_using_private_name_1; Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1;
} }
else { else {
// interface is inaccessible // interface is inaccessible
diagnosticMessage = Diagnostics.Extends_clause_of_exported_interface_0_has_or_is_using_private_name_1; diagnosticMessage = Diagnostics.extends_clause_of_exported_interface_0_has_or_is_using_private_name_1;
} }
return { return {
@ -1153,9 +1164,10 @@ namespace ts {
emitTypeParameters(node.typeParameters); emitTypeParameters(node.typeParameters);
const baseTypeNode = getClassExtendsHeritageClauseElement(node); const baseTypeNode = getClassExtendsHeritageClauseElement(node);
if (baseTypeNode) { if (baseTypeNode) {
emitHeritageClause([baseTypeNode], /*isImplementsList*/ false); node.name
emitHeritageClause(node.name, [baseTypeNode], /*isImplementsList*/ false);
} }
emitHeritageClause(getClassImplementsHeritageClauseElements(node), /*isImplementsList*/ true); emitHeritageClause(node.name, getClassImplementsHeritageClauseElements(node), /*isImplementsList*/ true);
write(" {"); write(" {");
writeLine(); writeLine();
increaseIndent(); increaseIndent();
@ -1177,7 +1189,7 @@ namespace ts {
emitTypeParameters(node.typeParameters); emitTypeParameters(node.typeParameters);
const interfaceExtendsTypes = filter(getInterfaceBaseTypeNodes(node), base => isEntityNameExpression(base.expression)); const interfaceExtendsTypes = filter(getInterfaceBaseTypeNodes(node), base => isEntityNameExpression(base.expression));
if (interfaceExtendsTypes && interfaceExtendsTypes.length) { if (interfaceExtendsTypes && interfaceExtendsTypes.length) {
emitHeritageClause(interfaceExtendsTypes, /*isImplementsList*/ false); emitHeritageClause(node.name, interfaceExtendsTypes, /*isImplementsList*/ false);
} }
write(" {"); write(" {");
writeLine(); writeLine();

View file

@ -2108,11 +2108,11 @@
"category": "Error", "category": "Error",
"code": 4019 "code": 4019
}, },
"Extends clause of exported class '{0}' has or is using private name '{1}'.": { "'extends' clause of exported class '{0}' has or is using private name '{1}'.": {
"category": "Error", "category": "Error",
"code": 4020 "code": 4020
}, },
"Extends clause of exported interface '{0}' has or is using private name '{1}'.": { "'extends' clause of exported interface '{0}' has or is using private name '{1}'.": {
"category": "Error", "category": "Error",
"code": 4022 "code": 4022
}, },
@ -2364,6 +2364,10 @@
"category": "Error", "category": "Error",
"code": 4092 "code": 4092
}, },
"'extends' clause of exported class '{0}' refers to a type whose name cannot be referenced.": {
"category": "Error",
"code": 4093
},
"The current host does not support the '{0}' option.": { "The current host does not support the '{0}' option.": {
"category": "Error", "category": "Error",
@ -3177,7 +3181,7 @@
"category": "Error", "category": "Error",
"code": 8016 "code": 8016
}, },
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clauses.": { "Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
"category": "Error", "category": "Error",
"code": 9002 "code": 9002
}, },

View file

@ -2480,6 +2480,7 @@
// with import statements it previously saw (but chose not to emit). // with import statements it previously saw (but chose not to emit).
trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void; trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
reportInaccessibleThisError(): void; reportInaccessibleThisError(): void;
reportIllegalExtends(): void;
} }
export const enum TypeFormatFlags { export const enum TypeFormatFlags {

View file

@ -67,7 +67,8 @@ namespace ts {
decreaseIndent: noop, decreaseIndent: noop,
clear: () => str = "", clear: () => str = "",
trackSymbol: noop, trackSymbol: noop,
reportInaccessibleThisError: noop reportInaccessibleThisError: noop,
reportIllegalExtends: noop
}; };
} }

View file

@ -1167,7 +1167,8 @@ namespace ts {
decreaseIndent: () => { indent--; }, decreaseIndent: () => { indent--; },
clear: resetWriter, clear: resetWriter,
trackSymbol: noop, trackSymbol: noop,
reportInaccessibleThisError: noop reportInaccessibleThisError: noop,
reportIllegalExtends: noop
}; };
function writeIndent() { function writeIndent() {
@ -1387,4 +1388,4 @@ namespace ts {
// First token is the open curly, this is where we want to put the 'super' call. // First token is the open curly, this is where we want to put the 'super' call.
return constructor.body.getFirstToken(sourceFile).getEnd(); return constructor.body.getFirstToken(sourceFile).getEnd();
} }
} }

View file

@ -1,5 +1,5 @@
tests/cases/compiler/declarationEmitExpressionInExtends3.ts(29,30): error TS4020: Extends clause of exported class 'MyClass' has or is using private name 'LocalClass'. tests/cases/compiler/declarationEmitExpressionInExtends3.ts(29,30): error TS4020: 'extends' clause of exported class 'MyClass' has or is using private name 'LocalClass'.
tests/cases/compiler/declarationEmitExpressionInExtends3.ts(37,31): error TS4020: Extends clause of exported class 'MyClass3' has or is using private name 'LocalInterface'. tests/cases/compiler/declarationEmitExpressionInExtends3.ts(37,31): error TS4020: 'extends' clause of exported class 'MyClass3' has or is using private name 'LocalInterface'.
==== tests/cases/compiler/declarationEmitExpressionInExtends3.ts (2 errors) ==== ==== tests/cases/compiler/declarationEmitExpressionInExtends3.ts (2 errors) ====
@ -33,7 +33,7 @@ tests/cases/compiler/declarationEmitExpressionInExtends3.ts(37,31): error TS4020
export class MyClass extends getLocalClass<LocalInterface>(undefined)<string, number> { // error LocalClass is inaccisible export class MyClass extends getLocalClass<LocalInterface>(undefined)<string, number> { // error LocalClass is inaccisible
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS4020: Extends clause of exported class 'MyClass' has or is using private name 'LocalClass'. !!! error TS4020: 'extends' clause of exported class 'MyClass' has or is using private name 'LocalClass'.
} }
@ -43,7 +43,7 @@ tests/cases/compiler/declarationEmitExpressionInExtends3.ts(37,31): error TS4020
export class MyClass3 extends getExportedClass<LocalInterface>(undefined)<LocalInterface> { // Error LocalInterface is inaccisble export class MyClass3 extends getExportedClass<LocalInterface>(undefined)<LocalInterface> { // Error LocalInterface is inaccisble
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS4020: Extends clause of exported class 'MyClass3' has or is using private name 'LocalInterface'. !!! error TS4020: 'extends' clause of exported class 'MyClass3' has or is using private name 'LocalInterface'.
} }

View file

@ -1,11 +1,13 @@
tests/cases/compiler/declarationEmitExpressionInExtends4.ts(2,10): error TS4060: Return type of exported function has or is using private name 'D'. tests/cases/compiler/declarationEmitExpressionInExtends4.ts(2,10): error TS4060: Return type of exported function has or is using private name 'D'.
tests/cases/compiler/declarationEmitExpressionInExtends4.ts(6,7): error TS4093: 'extends' clause of exported class 'C' refers to a type whose name cannot be referenced.
tests/cases/compiler/declarationEmitExpressionInExtends4.ts(6,17): error TS2315: Type 'D' is not generic. tests/cases/compiler/declarationEmitExpressionInExtends4.ts(6,17): error TS2315: Type 'D' is not generic.
tests/cases/compiler/declarationEmitExpressionInExtends4.ts(10,7): error TS4093: 'extends' clause of exported class 'C2' refers to a type whose name cannot be referenced.
tests/cases/compiler/declarationEmitExpressionInExtends4.ts(10,18): error TS2304: Cannot find name 'SomeUndefinedFunction'. tests/cases/compiler/declarationEmitExpressionInExtends4.ts(10,18): error TS2304: Cannot find name 'SomeUndefinedFunction'.
tests/cases/compiler/declarationEmitExpressionInExtends4.ts(15,18): error TS2304: Cannot find name 'SomeUndefinedFunction'. tests/cases/compiler/declarationEmitExpressionInExtends4.ts(15,18): error TS2304: Cannot find name 'SomeUndefinedFunction'.
tests/cases/compiler/declarationEmitExpressionInExtends4.ts(15,18): error TS4020: Extends clause of exported class 'C3' has or is using private name 'SomeUndefinedFunction'. tests/cases/compiler/declarationEmitExpressionInExtends4.ts(15,18): error TS4020: 'extends' clause of exported class 'C3' has or is using private name 'SomeUndefinedFunction'.
==== tests/cases/compiler/declarationEmitExpressionInExtends4.ts (5 errors) ==== ==== tests/cases/compiler/declarationEmitExpressionInExtends4.ts (7 errors) ====
function getSomething() { function getSomething() {
~~~~~~~~~~~~ ~~~~~~~~~~~~
@ -14,12 +16,16 @@ tests/cases/compiler/declarationEmitExpressionInExtends4.ts(15,18): error TS4020
} }
class C extends getSomething()<number, string> { class C extends getSomething()<number, string> {
~
!!! error TS4093: 'extends' clause of exported class 'C' refers to a type whose name cannot be referenced.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2315: Type 'D' is not generic. !!! error TS2315: Type 'D' is not generic.
} }
class C2 extends SomeUndefinedFunction()<number, string> { class C2 extends SomeUndefinedFunction()<number, string> {
~~
!!! error TS4093: 'extends' clause of exported class 'C2' refers to a type whose name cannot be referenced.
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
!!! error TS2304: Cannot find name 'SomeUndefinedFunction'. !!! error TS2304: Cannot find name 'SomeUndefinedFunction'.
@ -30,6 +36,6 @@ tests/cases/compiler/declarationEmitExpressionInExtends4.ts(15,18): error TS4020
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
!!! error TS2304: Cannot find name 'SomeUndefinedFunction'. !!! error TS2304: Cannot find name 'SomeUndefinedFunction'.
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
!!! error TS4020: Extends clause of exported class 'C3' has or is using private name 'SomeUndefinedFunction'. !!! error TS4020: 'extends' clause of exported class 'C3' has or is using private name 'SomeUndefinedFunction'.
} }

View file

@ -0,0 +1,39 @@
tests/cases/compiler/FinalClass.ts(4,14): error TS4093: 'extends' clause of exported class 'MyExtendedClass' refers to a type whose name cannot be referenced.
==== tests/cases/compiler/BaseClass.ts (0 errors) ====
export type Constructor<T> = new (...args: any[]) => T;
export class MyBaseClass<T> {
baseProperty: string;
constructor(value: T) {}
}
==== tests/cases/compiler/MixinClass.ts (0 errors) ====
import { Constructor, MyBaseClass } from './BaseClass';
export interface MyMixin {
mixinProperty: string;
}
export function MyMixin<T extends Constructor<MyBaseClass<any>>>(base: T): T & Constructor<MyMixin> {
return class extends base {
mixinProperty: string;
}
}
==== tests/cases/compiler/FinalClass.ts (1 errors) ====
import { MyBaseClass } from './BaseClass';
import { MyMixin } from './MixinClass';
export class MyExtendedClass extends MyMixin(MyBaseClass)<string> {
~~~~~~~~~~~~~~~
!!! error TS4093: 'extends' clause of exported class 'MyExtendedClass' refers to a type whose name cannot be referenced.
extendedClassProperty: number;
}
==== tests/cases/compiler/Main.ts (0 errors) ====
import { MyExtendedClass } from './FinalClass';
import { MyMixin } from './MixinClass';
const myExtendedClass = new MyExtendedClass('string');
const AnotherMixedClass = MyMixin(MyExtendedClass);

View file

@ -0,0 +1,114 @@
//// [tests/cases/compiler/exportClassExtendingIntersection.ts] ////
//// [BaseClass.ts]
export type Constructor<T> = new (...args: any[]) => T;
export class MyBaseClass<T> {
baseProperty: string;
constructor(value: T) {}
}
//// [MixinClass.ts]
import { Constructor, MyBaseClass } from './BaseClass';
export interface MyMixin {
mixinProperty: string;
}
export function MyMixin<T extends Constructor<MyBaseClass<any>>>(base: T): T & Constructor<MyMixin> {
return class extends base {
mixinProperty: string;
}
}
//// [FinalClass.ts]
import { MyBaseClass } from './BaseClass';
import { MyMixin } from './MixinClass';
export class MyExtendedClass extends MyMixin(MyBaseClass)<string> {
extendedClassProperty: number;
}
//// [Main.ts]
import { MyExtendedClass } from './FinalClass';
import { MyMixin } from './MixinClass';
const myExtendedClass = new MyExtendedClass('string');
const AnotherMixedClass = MyMixin(MyExtendedClass);
//// [BaseClass.js]
"use strict";
exports.__esModule = true;
var MyBaseClass = (function () {
function MyBaseClass(value) {
}
return MyBaseClass;
}());
exports.MyBaseClass = MyBaseClass;
//// [MixinClass.js]
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
function MyMixin(base) {
return (function (_super) {
__extends(class_1, _super);
function class_1() {
return _super !== null && _super.apply(this, arguments) || this;
}
return class_1;
}(base));
}
exports.MyMixin = MyMixin;
//// [FinalClass.js]
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var BaseClass_1 = require("./BaseClass");
var MixinClass_1 = require("./MixinClass");
var MyExtendedClass = (function (_super) {
__extends(MyExtendedClass, _super);
function MyExtendedClass() {
return _super !== null && _super.apply(this, arguments) || this;
}
return MyExtendedClass;
}(MixinClass_1.MyMixin(BaseClass_1.MyBaseClass)));
exports.MyExtendedClass = MyExtendedClass;
//// [Main.js]
"use strict";
exports.__esModule = true;
var FinalClass_1 = require("./FinalClass");
var MixinClass_1 = require("./MixinClass");
var myExtendedClass = new FinalClass_1.MyExtendedClass('string');
var AnotherMixedClass = MixinClass_1.MyMixin(FinalClass_1.MyExtendedClass);
//// [BaseClass.d.ts]
export declare type Constructor<T> = new (...args: any[]) => T;
export declare class MyBaseClass<T> {
baseProperty: string;
constructor(value: T);
}
//// [MixinClass.d.ts]
import { Constructor, MyBaseClass } from './BaseClass';
export interface MyMixin {
mixinProperty: string;
}
export declare function MyMixin<T extends Constructor<MyBaseClass<any>>>(base: T): T & Constructor<MyMixin>;
//// [Main.d.ts]

View file

@ -5,19 +5,25 @@ tests/cases/conformance/classes/mixinAccessModifiers.ts(51,4): error TS2445: Pro
tests/cases/conformance/classes/mixinAccessModifiers.ts(66,7): error TS2415: Class 'C1' incorrectly extends base class 'Private & Private2'. tests/cases/conformance/classes/mixinAccessModifiers.ts(66,7): error TS2415: Class 'C1' incorrectly extends base class 'Private & Private2'.
Type 'C1' is not assignable to type 'Private'. Type 'C1' is not assignable to type 'Private'.
Property 'p' has conflicting declarations and is inaccessible in type 'C1'. Property 'p' has conflicting declarations and is inaccessible in type 'C1'.
tests/cases/conformance/classes/mixinAccessModifiers.ts(66,7): error TS4093: 'extends' clause of exported class 'C1' refers to a type whose name cannot be referenced.
tests/cases/conformance/classes/mixinAccessModifiers.ts(67,7): error TS2415: Class 'C2' incorrectly extends base class 'Private & Protected'. tests/cases/conformance/classes/mixinAccessModifiers.ts(67,7): error TS2415: Class 'C2' incorrectly extends base class 'Private & Protected'.
Type 'C2' is not assignable to type 'Private'. Type 'C2' is not assignable to type 'Private'.
Property 'p' has conflicting declarations and is inaccessible in type 'C2'. Property 'p' has conflicting declarations and is inaccessible in type 'C2'.
tests/cases/conformance/classes/mixinAccessModifiers.ts(67,7): error TS4093: 'extends' clause of exported class 'C2' refers to a type whose name cannot be referenced.
tests/cases/conformance/classes/mixinAccessModifiers.ts(68,7): error TS2415: Class 'C3' incorrectly extends base class 'Private & Public'. tests/cases/conformance/classes/mixinAccessModifiers.ts(68,7): error TS2415: Class 'C3' incorrectly extends base class 'Private & Public'.
Type 'C3' is not assignable to type 'Private'. Type 'C3' is not assignable to type 'Private'.
Property 'p' has conflicting declarations and is inaccessible in type 'C3'. Property 'p' has conflicting declarations and is inaccessible in type 'C3'.
tests/cases/conformance/classes/mixinAccessModifiers.ts(68,7): error TS4093: 'extends' clause of exported class 'C3' refers to a type whose name cannot be referenced.
tests/cases/conformance/classes/mixinAccessModifiers.ts(70,7): error TS4093: 'extends' clause of exported class 'C4' refers to a type whose name cannot be referenced.
tests/cases/conformance/classes/mixinAccessModifiers.ts(83,7): error TS4093: 'extends' clause of exported class 'C5' refers to a type whose name cannot be referenced.
tests/cases/conformance/classes/mixinAccessModifiers.ts(85,6): error TS2445: Property 'p' is protected and only accessible within class 'C4' and its subclasses. tests/cases/conformance/classes/mixinAccessModifiers.ts(85,6): error TS2445: Property 'p' is protected and only accessible within class 'C4' and its subclasses.
tests/cases/conformance/classes/mixinAccessModifiers.ts(90,6): error TS2445: Property 's' is protected and only accessible within class 'typeof C4' and its subclasses. tests/cases/conformance/classes/mixinAccessModifiers.ts(90,6): error TS2445: Property 's' is protected and only accessible within class 'typeof C4' and its subclasses.
tests/cases/conformance/classes/mixinAccessModifiers.ts(96,7): error TS4093: 'extends' clause of exported class 'C6' refers to a type whose name cannot be referenced.
tests/cases/conformance/classes/mixinAccessModifiers.ts(98,6): error TS2445: Property 'p' is protected and only accessible within class 'C4' and its subclasses. tests/cases/conformance/classes/mixinAccessModifiers.ts(98,6): error TS2445: Property 'p' is protected and only accessible within class 'C4' and its subclasses.
tests/cases/conformance/classes/mixinAccessModifiers.ts(103,6): error TS2445: Property 's' is protected and only accessible within class 'typeof C4' and its subclasses. tests/cases/conformance/classes/mixinAccessModifiers.ts(103,6): error TS2445: Property 's' is protected and only accessible within class 'typeof C4' and its subclasses.
==== tests/cases/conformance/classes/mixinAccessModifiers.ts (11 errors) ==== ==== tests/cases/conformance/classes/mixinAccessModifiers.ts (17 errors) ====
type Constructable = new (...args: any[]) => object; type Constructable = new (...args: any[]) => object;
@ -96,18 +102,26 @@ tests/cases/conformance/classes/mixinAccessModifiers.ts(103,6): error TS2445: Pr
!!! error TS2415: Class 'C1' incorrectly extends base class 'Private & Private2'. !!! error TS2415: Class 'C1' incorrectly extends base class 'Private & Private2'.
!!! error TS2415: Type 'C1' is not assignable to type 'Private'. !!! error TS2415: Type 'C1' is not assignable to type 'Private'.
!!! error TS2415: Property 'p' has conflicting declarations and is inaccessible in type 'C1'. !!! error TS2415: Property 'p' has conflicting declarations and is inaccessible in type 'C1'.
~~
!!! error TS4093: 'extends' clause of exported class 'C1' refers to a type whose name cannot be referenced.
class C2 extends Mix(Private, Protected) {} class C2 extends Mix(Private, Protected) {}
~~ ~~
!!! error TS2415: Class 'C2' incorrectly extends base class 'Private & Protected'. !!! error TS2415: Class 'C2' incorrectly extends base class 'Private & Protected'.
!!! error TS2415: Type 'C2' is not assignable to type 'Private'. !!! error TS2415: Type 'C2' is not assignable to type 'Private'.
!!! error TS2415: Property 'p' has conflicting declarations and is inaccessible in type 'C2'. !!! error TS2415: Property 'p' has conflicting declarations and is inaccessible in type 'C2'.
~~
!!! error TS4093: 'extends' clause of exported class 'C2' refers to a type whose name cannot be referenced.
class C3 extends Mix(Private, Public) {} class C3 extends Mix(Private, Public) {}
~~ ~~
!!! error TS2415: Class 'C3' incorrectly extends base class 'Private & Public'. !!! error TS2415: Class 'C3' incorrectly extends base class 'Private & Public'.
!!! error TS2415: Type 'C3' is not assignable to type 'Private'. !!! error TS2415: Type 'C3' is not assignable to type 'Private'.
!!! error TS2415: Property 'p' has conflicting declarations and is inaccessible in type 'C3'. !!! error TS2415: Property 'p' has conflicting declarations and is inaccessible in type 'C3'.
~~
!!! error TS4093: 'extends' clause of exported class 'C3' refers to a type whose name cannot be referenced.
class C4 extends Mix(Protected, Protected2) { class C4 extends Mix(Protected, Protected2) {
~~
!!! error TS4093: 'extends' clause of exported class 'C4' refers to a type whose name cannot be referenced.
f(c4: C4, c5: C5, c6: C6) { f(c4: C4, c5: C5, c6: C6) {
c4.p; c4.p;
c5.p; c5.p;
@ -121,6 +135,8 @@ tests/cases/conformance/classes/mixinAccessModifiers.ts(103,6): error TS2445: Pr
} }
class C5 extends Mix(Protected, Public) { class C5 extends Mix(Protected, Public) {
~~
!!! error TS4093: 'extends' clause of exported class 'C5' refers to a type whose name cannot be referenced.
f(c4: C4, c5: C5, c6: C6) { f(c4: C4, c5: C5, c6: C6) {
c4.p; // Error, not in class deriving from Protected2 c4.p; // Error, not in class deriving from Protected2
~ ~
@ -138,6 +154,8 @@ tests/cases/conformance/classes/mixinAccessModifiers.ts(103,6): error TS2445: Pr
} }
class C6 extends Mix(Public, Public2) { class C6 extends Mix(Public, Public2) {
~~
!!! error TS4093: 'extends' clause of exported class 'C6' refers to a type whose name cannot be referenced.
f(c4: C4, c5: C5, c6: C6) { f(c4: C4, c5: C5, c6: C6) {
c4.p; // Error, not in class deriving from Protected2 c4.p; // Error, not in class deriving from Protected2
~ ~

View file

@ -264,60 +264,3 @@ var C6 = (function (_super) {
}; };
return C6; return C6;
}(Mix(Public, Public2))); }(Mix(Public, Public2)));
//// [mixinAccessModifiers.d.ts]
declare type Constructable = new (...args: any[]) => object;
declare class Private {
constructor(...args: any[]);
private p;
}
declare class Private2 {
constructor(...args: any[]);
private p;
}
declare class Protected {
constructor(...args: any[]);
protected p: string;
protected static s: string;
}
declare class Protected2 {
constructor(...args: any[]);
protected p: string;
protected static s: string;
}
declare class Public {
constructor(...args: any[]);
p: string;
static s: string;
}
declare class Public2 {
constructor(...args: any[]);
p: string;
static s: string;
}
declare function f1(x: Private & Private2): void;
declare function f2(x: Private & Protected): void;
declare function f3(x: Private & Public): void;
declare function f4(x: Protected & Protected2): void;
declare function f5(x: Protected & Public): void;
declare function f6(x: Public & Public2): void;
declare function Mix<T, U>(c1: T, c2: U): T & U;
declare class C1 extends Private & Private2 {
}
declare class C2 extends Private & Protected {
}
declare class C3 extends Private & Public {
}
declare class C4 extends Protected & Protected2 {
f(c4: C4, c5: C5, c6: C6): void;
static g(): void;
}
declare class C5 extends Protected & Public {
f(c4: C4, c5: C5, c6: C6): void;
static g(): void;
}
declare class C6 extends Public & Public2 {
f(c4: C4, c5: C5, c6: C6): void;
static g(): void;
}

View file

@ -1,10 +1,10 @@
tests/cases/compiler/privacyClassExtendsClauseDeclFile_GlobalFile.ts(16,67): error TS4020: Extends clause of exported class 'publicClassExtendingPrivateClassInModule' has or is using private name 'privateClassInPublicModule'. tests/cases/compiler/privacyClassExtendsClauseDeclFile_GlobalFile.ts(16,67): error TS4020: 'extends' clause of exported class 'publicClassExtendingPrivateClassInModule' has or is using private name 'privateClassInPublicModule'.
tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(17,67): error TS4020: Extends clause of exported class 'publicClassExtendingPrivateClassInModule' has or is using private name 'privateClassInPublicModule'. tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(17,67): error TS4020: 'extends' clause of exported class 'publicClassExtendingPrivateClassInModule' has or is using private name 'privateClassInPublicModule'.
tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(20,63): error TS2690: A class must be declared after its base class. tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(20,63): error TS2690: A class must be declared after its base class.
tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(22,69): error TS4020: Extends clause of exported class 'publicClassExtendingFromPrivateModuleClass' has or is using private name 'privateModule'. tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(22,69): error TS4020: 'extends' clause of exported class 'publicClassExtendingFromPrivateModuleClass' has or is using private name 'privateModule'.
tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(22,69): error TS2690: A class must be declared after its base class. tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(22,69): error TS2690: A class must be declared after its base class.
tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(64,55): error TS4020: Extends clause of exported class 'publicClassExtendingPrivateClass' has or is using private name 'privateClass'. tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(64,55): error TS4020: 'extends' clause of exported class 'publicClassExtendingPrivateClass' has or is using private name 'privateClass'.
tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(69,65): error TS4020: Extends clause of exported class 'publicClassExtendingFromPrivateModuleClass' has or is using private name 'privateModule'. tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(69,65): error TS4020: 'extends' clause of exported class 'publicClassExtendingFromPrivateModuleClass' has or is using private name 'privateModule'.
==== tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts (6 errors) ==== ==== tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts (6 errors) ====
@ -26,7 +26,7 @@ tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(69,65):
} }
export class publicClassExtendingPrivateClassInModule extends privateClassInPublicModule { // Should error export class publicClassExtendingPrivateClassInModule extends privateClassInPublicModule { // Should error
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS4020: Extends clause of exported class 'publicClassExtendingPrivateClassInModule' has or is using private name 'privateClassInPublicModule'. !!! error TS4020: 'extends' clause of exported class 'publicClassExtendingPrivateClassInModule' has or is using private name 'privateClassInPublicModule'.
} }
class privateClassExtendingFromPrivateModuleClass extends privateModule.publicClassInPrivateModule { class privateClassExtendingFromPrivateModuleClass extends privateModule.publicClassInPrivateModule {
@ -35,7 +35,7 @@ tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(69,65):
} }
export class publicClassExtendingFromPrivateModuleClass extends privateModule.publicClassInPrivateModule { // Should error export class publicClassExtendingFromPrivateModuleClass extends privateModule.publicClassInPrivateModule { // Should error
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
!!! error TS4020: Extends clause of exported class 'publicClassExtendingFromPrivateModuleClass' has or is using private name 'privateModule'. !!! error TS4020: 'extends' clause of exported class 'publicClassExtendingFromPrivateModuleClass' has or is using private name 'privateModule'.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2690: A class must be declared after its base class. !!! error TS2690: A class must be declared after its base class.
} }
@ -81,14 +81,14 @@ tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(69,65):
} }
export class publicClassExtendingPrivateClass extends privateClass { // Should error export class publicClassExtendingPrivateClass extends privateClass { // Should error
~~~~~~~~~~~~ ~~~~~~~~~~~~
!!! error TS4020: Extends clause of exported class 'publicClassExtendingPrivateClass' has or is using private name 'privateClass'. !!! error TS4020: 'extends' clause of exported class 'publicClassExtendingPrivateClass' has or is using private name 'privateClass'.
} }
class privateClassExtendingFromPrivateModuleClass extends privateModule.publicClassInPrivateModule { class privateClassExtendingFromPrivateModuleClass extends privateModule.publicClassInPrivateModule {
} }
export class publicClassExtendingFromPrivateModuleClass extends privateModule.publicClassInPrivateModule { // Should error export class publicClassExtendingFromPrivateModuleClass extends privateModule.publicClassInPrivateModule { // Should error
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
!!! error TS4020: Extends clause of exported class 'publicClassExtendingFromPrivateModuleClass' has or is using private name 'privateModule'. !!! error TS4020: 'extends' clause of exported class 'publicClassExtendingFromPrivateModuleClass' has or is using private name 'privateModule'.
} }
==== tests/cases/compiler/privacyClassExtendsClauseDeclFile_GlobalFile.ts (1 errors) ==== ==== tests/cases/compiler/privacyClassExtendsClauseDeclFile_GlobalFile.ts (1 errors) ====
@ -109,7 +109,7 @@ tests/cases/compiler/privacyClassExtendsClauseDeclFile_externalModule.ts(69,65):
} }
export class publicClassExtendingPrivateClassInModule extends privateClassInPublicModule { // Should error export class publicClassExtendingPrivateClassInModule extends privateClassInPublicModule { // Should error
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS4020: Extends clause of exported class 'publicClassExtendingPrivateClassInModule' has or is using private name 'privateClassInPublicModule'. !!! error TS4020: 'extends' clause of exported class 'publicClassExtendingPrivateClassInModule' has or is using private name 'privateClassInPublicModule'.
} }
} }
class publicClassInGlobal { class publicClassInGlobal {

View file

@ -1,9 +1,9 @@
tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_GlobalFile.ts(14,82): error TS4022: Extends clause of exported interface 'publicInterfaceImplementingPrivateInterfaceInModule' has or is using private name 'privateInterfaceInPublicModule'. tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_GlobalFile.ts(14,82): error TS4022: 'extends' clause of exported interface 'publicInterfaceImplementingPrivateInterfaceInModule' has or is using private name 'privateInterfaceInPublicModule'.
tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts(15,82): error TS4022: Extends clause of exported interface 'publicInterfaceImplementingPrivateInterfaceInModule' has or is using private name 'privateInterfaceInPublicModule'. tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts(15,82): error TS4022: 'extends' clause of exported interface 'publicInterfaceImplementingPrivateInterfaceInModule' has or is using private name 'privateInterfaceInPublicModule'.
tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts(20,84): error TS4022: Extends clause of exported interface 'publicInterfaceImplementingFromPrivateModuleInterface' has or is using private name 'privateModule'. tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts(20,84): error TS4022: 'extends' clause of exported interface 'publicInterfaceImplementingFromPrivateModuleInterface' has or is using private name 'privateModule'.
tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts(23,83): error TS4022: Extends clause of exported interface 'publicInterfaceImplementingPrivateAndPublicInterface' has or is using private name 'privateInterfaceInPublicModule'. tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts(23,83): error TS4022: 'extends' clause of exported interface 'publicInterfaceImplementingPrivateAndPublicInterface' has or is using private name 'privateInterfaceInPublicModule'.
tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts(63,70): error TS4022: Extends clause of exported interface 'publicInterfaceImplementingPrivateInterface' has or is using private name 'privateInterface'. tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts(63,70): error TS4022: 'extends' clause of exported interface 'publicInterfaceImplementingPrivateInterface' has or is using private name 'privateInterface'.
tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts(68,80): error TS4022: Extends clause of exported interface 'publicInterfaceImplementingFromPrivateModuleInterface' has or is using private name 'privateModule'. tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts(68,80): error TS4022: 'extends' clause of exported interface 'publicInterfaceImplementingFromPrivateModuleInterface' has or is using private name 'privateModule'.
==== tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts (5 errors) ==== ==== tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts (5 errors) ====
@ -23,19 +23,19 @@ tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts(68,
} }
export interface publicInterfaceImplementingPrivateInterfaceInModule extends privateInterfaceInPublicModule { // Should error export interface publicInterfaceImplementingPrivateInterfaceInModule extends privateInterfaceInPublicModule { // Should error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS4022: Extends clause of exported interface 'publicInterfaceImplementingPrivateInterfaceInModule' has or is using private name 'privateInterfaceInPublicModule'. !!! error TS4022: 'extends' clause of exported interface 'publicInterfaceImplementingPrivateInterfaceInModule' has or is using private name 'privateInterfaceInPublicModule'.
} }
interface privateInterfaceImplementingFromPrivateModuleInterface extends privateModule.publicInterfaceInPrivateModule { interface privateInterfaceImplementingFromPrivateModuleInterface extends privateModule.publicInterfaceInPrivateModule {
} }
export interface publicInterfaceImplementingFromPrivateModuleInterface extends privateModule.publicInterfaceInPrivateModule { // Should error export interface publicInterfaceImplementingFromPrivateModuleInterface extends privateModule.publicInterfaceInPrivateModule { // Should error
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
!!! error TS4022: Extends clause of exported interface 'publicInterfaceImplementingFromPrivateModuleInterface' has or is using private name 'privateModule'. !!! error TS4022: 'extends' clause of exported interface 'publicInterfaceImplementingFromPrivateModuleInterface' has or is using private name 'privateModule'.
} }
export interface publicInterfaceImplementingPrivateAndPublicInterface extends privateInterfaceInPublicModule, publicInterfaceInPublicModule { // Should error export interface publicInterfaceImplementingPrivateAndPublicInterface extends privateInterfaceInPublicModule, publicInterfaceInPublicModule { // Should error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS4022: Extends clause of exported interface 'publicInterfaceImplementingPrivateAndPublicInterface' has or is using private name 'privateInterfaceInPublicModule'. !!! error TS4022: 'extends' clause of exported interface 'publicInterfaceImplementingPrivateAndPublicInterface' has or is using private name 'privateInterfaceInPublicModule'.
} }
} }
@ -77,14 +77,14 @@ tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts(68,
} }
export interface publicInterfaceImplementingPrivateInterface extends privateInterface { // Should error export interface publicInterfaceImplementingPrivateInterface extends privateInterface { // Should error
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
!!! error TS4022: Extends clause of exported interface 'publicInterfaceImplementingPrivateInterface' has or is using private name 'privateInterface'. !!! error TS4022: 'extends' clause of exported interface 'publicInterfaceImplementingPrivateInterface' has or is using private name 'privateInterface'.
} }
interface privateInterfaceImplementingFromPrivateModuleInterface extends privateModule.publicInterfaceInPrivateModule { interface privateInterfaceImplementingFromPrivateModuleInterface extends privateModule.publicInterfaceInPrivateModule {
} }
export interface publicInterfaceImplementingFromPrivateModuleInterface extends privateModule.publicInterfaceInPrivateModule { // Should error export interface publicInterfaceImplementingFromPrivateModuleInterface extends privateModule.publicInterfaceInPrivateModule { // Should error
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
!!! error TS4022: Extends clause of exported interface 'publicInterfaceImplementingFromPrivateModuleInterface' has or is using private name 'privateModule'. !!! error TS4022: 'extends' clause of exported interface 'publicInterfaceImplementingFromPrivateModuleInterface' has or is using private name 'privateModule'.
} }
==== tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_GlobalFile.ts (1 errors) ==== ==== tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_GlobalFile.ts (1 errors) ====
@ -103,7 +103,7 @@ tests/cases/compiler/privacyInterfaceExtendsClauseDeclFile_externalModule.ts(68,
} }
export interface publicInterfaceImplementingPrivateInterfaceInModule extends privateInterfaceInPublicModule { // Should error export interface publicInterfaceImplementingPrivateInterfaceInModule extends privateInterfaceInPublicModule { // Should error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS4022: Extends clause of exported interface 'publicInterfaceImplementingPrivateInterfaceInModule' has or is using private name 'privateInterfaceInPublicModule'. !!! error TS4022: 'extends' clause of exported interface 'publicInterfaceImplementingPrivateInterfaceInModule' has or is using private name 'privateInterfaceInPublicModule'.
} }
} }
interface publicInterfaceInGlobal { interface publicInterfaceInGlobal {

View file

@ -0,0 +1,34 @@
// @declaration: true
// @Filename:BaseClass.ts
export type Constructor<T> = new (...args: any[]) => T;
export class MyBaseClass<T> {
baseProperty: string;
constructor(value: T) {}
}
// @Filename:MixinClass.ts
import { Constructor, MyBaseClass } from './BaseClass';
export interface MyMixin {
mixinProperty: string;
}
export function MyMixin<T extends Constructor<MyBaseClass<any>>>(base: T): T & Constructor<MyMixin> {
return class extends base {
mixinProperty: string;
}
}
// @Filename:FinalClass.ts
import { MyBaseClass } from './BaseClass';
import { MyMixin } from './MixinClass';
export class MyExtendedClass extends MyMixin(MyBaseClass)<string> {
extendedClassProperty: number;
}
// @Filename:Main.ts
import { MyExtendedClass } from './FinalClass';
import { MyMixin } from './MixinClass';
const myExtendedClass = new MyExtendedClass('string');
const AnotherMixedClass = MyMixin(MyExtendedClass);