Add supertype tests and add TSAbstractClassProperty (#1467)

* feat(typescript): add supertype tests and add TSAbstractClassProperty

* chore(typescript): bump parser version

* fix(flow): allow both variance and accessibility mods
master
Lucas Azzola 2017-05-01 10:41:19 +10:00 committed by Christopher Chedeau
parent 3161bd0787
commit 7d1e24ea7d
25 changed files with 1386 additions and 24 deletions

View File

@ -32,8 +32,8 @@
"rollup-plugin-node-builtins": "2.0.0",
"rollup-plugin-node-globals": "1.1.0",
"rollup-plugin-node-resolve": "2.0.0",
"typescript": "2.2.1",
"typescript-eslint-parser": "git://github.com/eslint/typescript-eslint-parser.git#bfb1506c48b625871ffeb67dbec7941d460f8941"
"typescript": "2.3.2",
"typescript-eslint-parser": "git://github.com/eslint/typescript-eslint-parser.git#a294afa8158c9c088521eed72b6745eed302361c"
},
"scripts": {
"test": "jest",

View File

@ -1447,30 +1447,22 @@ function genericPrintNoParens(path, options, print, args) {
return concat(parts);
case "ClassProperty":
case "TSAbstractClassProperty":
if (n.static) parts.push("static ");
var key;
var variance = getFlowVariance(n, options);
if (variance) parts.push(variance);
if (n.accessibility) parts.push(n.accessibility + " ");
if (n.type === "TSAbstractClassProperty") parts.push("abstract ");
if (n.computed) {
key = concat(["[", path.call(print, "key"), "]"]);
parts.push("[", path.call(print, "key"), "]");
} else {
key = printPropertyKey(path, options, print);
var variance = getFlowVariance(n, options);
if (variance) {
key = concat([variance, key]);
} else if (n.accessibility === "public") {
key = concat(["public ", key]);
} else if (n.accessibility === "protected") {
key = concat(["protected ", key]);
} else if (n.accessibility === "private") {
key = concat(["private ", key]);
}
parts.push(printPropertyKey(path, options, print));
}
parts.push(key);
if (n.typeAnnotation) parts.push(": ", path.call(print, "typeAnnotation"));
if (n.value) parts.push(" = ", path.call(print, "value"));
@ -3598,6 +3590,7 @@ function classChildNeedsASIProtection(node) {
switch (node.type) {
case "ClassProperty":
case "TSAbstractClassProperty":
return node.computed;
// flow
case "MethodDefinition":

View File

@ -0,0 +1,735 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`classExpression.ts 1`] = `
var x = class C {
}
var y = {
foo: class C2 {
}
}
var z = class C4 {
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var x = class C {};
var y = {
foo: class C2 {}
};
var z = class C4 {};
`;
exports[`mixinAccessModifiers.ts 1`] = `
// @declaration: true
type Constructable = new (...args: any[]) => object;
class Private {
constructor (...args: any[]) {}
private p: string;
}
class Private2 {
constructor (...args: any[]) {}
private p: string;
}
class Protected {
constructor (...args: any[]) {}
protected p: string;
protected static s: string;
}
class Protected2 {
constructor (...args: any[]) {}
protected p: string;
protected static s: string;
}
class Public {
constructor (...args: any[]) {}
public p: string;
public static s: string;
}
class Public2 {
constructor (...args: any[]) {}
public p: string;
public static s: string;
}
function f1(x: Private & Private2) {
x.p; // Error, private constituent makes property inaccessible
}
function f2(x: Private & Protected) {
x.p; // Error, private constituent makes property inaccessible
}
function f3(x: Private & Public) {
x.p; // Error, private constituent makes property inaccessible
}
function f4(x: Protected & Protected2) {
x.p; // Error, protected when all constituents are protected
}
function f5(x: Protected & Public) {
x.p; // Ok, public if any constituent is public
}
function f6(x: Public & Public2) {
x.p; // Ok, public if any constituent is public
}
declare function Mix<T, U>(c1: T, c2: U): T & U;
// Can't derive from type with inaccessible properties
class C1 extends Mix(Private, Private2) {}
class C2 extends Mix(Private, Protected) {}
class C3 extends Mix(Private, Public) {}
class C4 extends Mix(Protected, Protected2) {
f(c4: C4, c5: C5, c6: C6) {
c4.p;
c5.p;
c6.p;
}
static g() {
C4.s;
C5.s;
C6.s
}
}
class C5 extends Mix(Protected, Public) {
f(c4: C4, c5: C5, c6: C6) {
c4.p; // Error, not in class deriving from Protected2
c5.p;
c6.p;
}
static g() {
C4.s; // Error, not in class deriving from Protected2
C5.s;
C6.s
}
}
class C6 extends Mix(Public, Public2) {
f(c4: C4, c5: C5, c6: C6) {
c4.p; // Error, not in class deriving from Protected2
c5.p;
c6.p;
}
static g() {
C4.s; // Error, not in class deriving from Protected2
C5.s;
C6.s
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @declaration: true
type Constructable = new(...args: any[]) => object;
class Private {
constructor(...args: any[]) {}
private p: string;
}
class Private2 {
constructor(...args: any[]) {}
private p: string;
}
class Protected {
constructor(...args: any[]) {}
protected p: string;
static protected s: string;
}
class Protected2 {
constructor(...args: any[]) {}
protected p: string;
static protected s: string;
}
class Public {
constructor(...args: any[]) {}
public p: string;
static public s: string;
}
class Public2 {
constructor(...args: any[]) {}
public p: string;
static public s: string;
}
function f1(x: Private & Private2) {
x.p; // Error, private constituent makes property inaccessible
}
function f2(x: Private & Protected) {
x.p; // Error, private constituent makes property inaccessible
}
function f3(x: Private & Public) {
x.p; // Error, private constituent makes property inaccessible
}
function f4(x: Protected & Protected2) {
x.p; // Error, protected when all constituents are protected
}
function f5(x: Protected & Public) {
x.p; // Ok, public if any constituent is public
}
function f6(x: Public & Public2) {
x.p; // Ok, public if any constituent is public
}
declare function Mix<T, U>(c1: T, c2: U): T & U
// Can't derive from type with inaccessible properties
class C1 extends Mix(Private, Private2) {}
class C2 extends Mix(Private, Protected) {}
class C3 extends Mix(Private, Public) {}
class C4 extends Mix(Protected, Protected2) {
f(c4: C4, c5: C5, c6: C6) {
c4.p;
c5.p;
c6.p;
}
static g() {
C4.s;
C5.s;
C6.s;
}
}
class C5 extends Mix(Protected, Public) {
f(c4: C4, c5: C5, c6: C6) {
c4.p; // Error, not in class deriving from Protected2
c5.p;
c6.p;
}
static g() {
C4.s; // Error, not in class deriving from Protected2
C5.s;
C6.s;
}
}
class C6 extends Mix(Public, Public2) {
f(c4: C4, c5: C5, c6: C6) {
c4.p; // Error, not in class deriving from Protected2
c5.p;
c6.p;
}
static g() {
C4.s; // Error, not in class deriving from Protected2
C5.s;
C6.s;
}
}
`;
exports[`mixinClassesAnnotated.ts 1`] = `
// @declaration: true
type Constructor<T> = new(...args: any[]) => T;
class Base {
constructor(public x: number, public y: number) {}
}
class Derived extends Base {
constructor(x: number, y: number, public z: number) {
super(x, y);
}
}
const Printable = <T extends Constructor<Base>>(superClass: T): Constructor<Printable> & { message: string } & T =>
class extends superClass {
static message = "hello";
print() {
const output = this.x + "," + this.y;
}
}
function Tagged<T extends Constructor<{}>>(superClass: T): Constructor<Tagged> & T {
class C extends superClass {
_tag: string;
constructor(...args: any[]) {
super(...args);
this._tag = "hello";
}
}
return C;
}
const Thing1 = Tagged(Derived);
const Thing2 = Tagged(Printable(Derived));
Thing2.message;
function f1() {
const thing = new Thing1(1, 2, 3);
thing.x;
thing._tag;
}
function f2() {
const thing = new Thing2(1, 2, 3);
thing.x;
thing._tag;
thing.print();
}
class Thing3 extends Thing2 {
constructor(tag: string) {
super(10, 20, 30);
this._tag = tag;
}
test() {
this.print();
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @declaration: true
type Constructor<T> = new(...args: any[]) => T;
class Base {
constructor(public x: number, public y: number) {}
}
class Derived extends Base {
constructor(x: number, y: number, public z: number) {
super(x, y);
}
}
const Printable = <T extends Constructor<Base>>(
superClass: T
): Constructor<Printable> & { message: string } & T => class
extends superClass {
static message = "hello";
print() {
const output = this.x + "," + this.y;
}
};
function Tagged<T extends Constructor<{}>>(
superClass: T
): Constructor<Tagged> & T {
class C extends superClass {
_tag: string;
constructor(...args: any[]) {
super(...args);
this._tag = "hello";
}
}
return C;
}
const Thing1 = Tagged(Derived);
const Thing2 = Tagged(Printable(Derived));
Thing2.message;
function f1() {
const thing = new Thing1(1, 2, 3);
thing.x;
thing._tag;
}
function f2() {
const thing = new Thing2(1, 2, 3);
thing.x;
thing._tag;
thing.print();
}
class Thing3 extends Thing2 {
constructor(tag: string) {
super(10, 20, 30);
this._tag = tag;
}
test() {
this.print();
}
}
`;
exports[`mixinClassesAnonymous.ts 1`] = `
type Constructor<T> = new(...args: any[]) => T;
class Base {
constructor(public x: number, public y: number) {}
}
class Derived extends Base {
constructor(x: number, y: number, public z: number) {
super(x, y);
}
}
const Printable = <T extends Constructor<Base>>(superClass: T) => class extends superClass {
static message = "hello";
print() {
const output = this.x + "," + this.y;
}
}
function Tagged<T extends Constructor<{}>>(superClass: T) {
class C extends superClass {
_tag: string;
constructor(...args: any[]) {
super(...args);
this._tag = "hello";
}
}
return C;
}
const Thing1 = Tagged(Derived);
const Thing2 = Tagged(Printable(Derived));
Thing2.message;
function f1() {
const thing = new Thing1(1, 2, 3);
thing.x;
thing._tag;
}
function f2() {
const thing = new Thing2(1, 2, 3);
thing.x;
thing._tag;
thing.print();
}
class Thing3 extends Thing2 {
constructor(tag: string) {
super(10, 20, 30);
this._tag = tag;
}
test() {
this.print();
}
}
// Repro from #13805
const Timestamped = <CT extends Constructor<object>>(Base: CT) => {
return class extends Base {
timestamp = new Date();
};
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
type Constructor<T> = new(...args: any[]) => T;
class Base {
constructor(public x: number, public y: number) {}
}
class Derived extends Base {
constructor(x: number, y: number, public z: number) {
super(x, y);
}
}
const Printable = <T extends Constructor<Base>>(superClass: T) => class
extends superClass {
static message = "hello";
print() {
const output = this.x + "," + this.y;
}
};
function Tagged<T extends Constructor<{}>>(superClass: T) {
class C extends superClass {
_tag: string;
constructor(...args: any[]) {
super(...args);
this._tag = "hello";
}
}
return C;
}
const Thing1 = Tagged(Derived);
const Thing2 = Tagged(Printable(Derived));
Thing2.message;
function f1() {
const thing = new Thing1(1, 2, 3);
thing.x;
thing._tag;
}
function f2() {
const thing = new Thing2(1, 2, 3);
thing.x;
thing._tag;
thing.print();
}
class Thing3 extends Thing2 {
constructor(tag: string) {
super(10, 20, 30);
this._tag = tag;
}
test() {
this.print();
}
}
// Repro from #13805
const Timestamped = <CT extends Constructor<object>>(Base: CT) => {
return class extends Base {
timestamp = new Date();
};
};
`;
exports[`mixinClassesMembers.ts 1`] = `
// @declaration: true
declare class C1 {
public a: number;
protected b: number;
private c: number;
constructor(s: string);
constructor(n: number);
}
declare class M1 {
constructor(...args: any[]);
p: number;
static p: number;
}
declare class M2 {
constructor(...args: any[]);
f(): number;
static f(): number;
}
declare const Mixed1: typeof M1 & typeof C1;
declare const Mixed2: typeof C1 & typeof M1;
declare const Mixed3: typeof M2 & typeof M1 & typeof C1;
declare const Mixed4: typeof C1 & typeof M1 & typeof M2;
declare const Mixed5: typeof M1 & typeof M2;
function f1() {
let x1 = new Mixed1("hello");
let x2 = new Mixed1(42);
let x3 = new Mixed2("hello");
let x4 = new Mixed2(42);
let x5 = new Mixed3("hello");
let x6 = new Mixed3(42);
let x7 = new Mixed4("hello");
let x8 = new Mixed4(42);
let x9 = new Mixed5();
}
function f2() {
let x = new Mixed1("hello");
x.a;
x.p;
Mixed1.p;
}
function f3() {
let x = new Mixed2("hello");
x.a;
x.p;
Mixed2.p;
}
function f4() {
let x = new Mixed3("hello");
x.a;
x.p;
x.f();
Mixed3.p;
Mixed3.f();
}
function f5() {
let x = new Mixed4("hello");
x.a;
x.p;
x.f();
Mixed4.p;
Mixed4.f();
}
function f6() {
let x = new Mixed5();
x.p;
x.f();
Mixed5.p;
Mixed5.f();
}
class C2 extends Mixed1 {
constructor() {
super("hello");
this.a;
this.b;
this.p;
}
}
class C3 extends Mixed3 {
constructor() {
super(42);
this.a;
this.b;
this.p;
this.f();
}
f() { return super.f(); }
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @declaration: true
declare class C1 {
public a: number;
protected b: number;
private c: number;
constructor(s: string);
constructor(n: number);
}
declare class M1 {
constructor(...args: any[]);
p: number;
static p: number;
}
declare class M2 {
constructor(...args: any[]);
f(): number;
static f(): number;
}
declare const Mixed1: typeof M1 & typeof C1;
declare const Mixed2: typeof C1 & typeof M1;
declare const Mixed3: typeof M2 & typeof M1 & typeof C1;
declare const Mixed4: typeof C1 & typeof M1 & typeof M2;
declare const Mixed5: typeof M1 & typeof M2;
function f1() {
let x1 = new Mixed1("hello");
let x2 = new Mixed1(42);
let x3 = new Mixed2("hello");
let x4 = new Mixed2(42);
let x5 = new Mixed3("hello");
let x6 = new Mixed3(42);
let x7 = new Mixed4("hello");
let x8 = new Mixed4(42);
let x9 = new Mixed5();
}
function f2() {
let x = new Mixed1("hello");
x.a;
x.p;
Mixed1.p;
}
function f3() {
let x = new Mixed2("hello");
x.a;
x.p;
Mixed2.p;
}
function f4() {
let x = new Mixed3("hello");
x.a;
x.p;
x.f();
Mixed3.p;
Mixed3.f();
}
function f5() {
let x = new Mixed4("hello");
x.a;
x.p;
x.f();
Mixed4.p;
Mixed4.f();
}
function f6() {
let x = new Mixed5();
x.p;
x.f();
Mixed5.p;
Mixed5.f();
}
class C2 extends Mixed1 {
constructor() {
super("hello");
this.a;
this.b;
this.p;
}
}
class C3 extends Mixed3 {
constructor() {
super(42);
this.a;
this.b;
this.p;
this.f();
}
f() {
return super.f();
}
}
`;
exports[`nestedClassDeclaration.ts 1`] = `
// nested classes are not allowed
class C {
x: string;
}
function foo() {
class C3 {
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// nested classes are not allowed
class C {
x: string;
}
function foo() {
class C3 {}
}
`;

View File

@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`classInsideBlock.ts 1`] = `
function foo() {
class C { }
}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function foo() {
class C {}
}
`;

View File

@ -658,13 +658,27 @@ class DD extends BB {
`;
exports[`classAbstractProperties.ts 1`] = `
abstract class A {
abstract class A {
abstract x : number;
public abstract y : number;
protected abstract z : number;
private abstract w : number;
abstract m: () => void;
abstract foo_x() : number;
public abstract foo_y() : number;
protected abstract foo_z() : number;
private abstract foo_w() : number;
}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
abstract class A {
abstract x: number;
public abstract y: number;
protected abstract z: number;
private abstract w: number;
abstract m: () => void;
abstract foo_x(): number;
public abstract foo_y(): number;
protected abstract foo_z(): number;

View File

@ -1,4 +1,11 @@
abstract class A {
abstract class A {
abstract x : number;
public abstract y : number;
protected abstract z : number;
private abstract w : number;
abstract m: () => void;
abstract foo_x() : number;
public abstract foo_y() : number;
protected abstract foo_z() : number;

View File

@ -0,0 +1,145 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`classAppearsToHaveMembersOfObject.ts 1`] = `
class C { foo: string; }
var c: C;
var r = c.toString();
var r2 = c.hasOwnProperty('');
var o: Object = c;
var o2: {} = c;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class C {
foo: string;
}
var c: C;
var r = c.toString();
var r2 = c.hasOwnProperty("");
var o: Object = c;
var o2: {} = c;
`;
exports[`classExtendingClass.ts 1`] = `
class C {
foo: string;
thing() { }
static other() { }
}
class D extends C {
bar: string;
}
var d: D;
var r = d.foo;
var r2 = d.bar;
var r3 = d.thing();
var r4 = D.other();
class C2<T> {
foo: T;
thing(x: T) { }
static other<T>(x: T) { }
}
class D2<T> extends C2<T> {
bar: string;
}
var d2: D2<string>;
var r5 = d2.foo;
var r6 = d2.bar;
var r7 = d2.thing('');
var r8 = D2.other(1);~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class C {
foo: string;
thing() {}
static other() {}
}
class D extends C {
bar: string;
}
var d: D;
var r = d.foo;
var r2 = d.bar;
var r3 = d.thing();
var r4 = D.other();
class C2<T> {
foo: T;
thing(x: T) {}
static other<T>(x: T) {}
}
class D2<T> extends C2<T> {
bar: string;
}
var d2: D2<string>;
var r5 = d2.foo;
var r6 = d2.bar;
var r7 = d2.thing("");
var r8 = D2.other(1);
`;
exports[`classExtendsItselfIndirectly.ts 1`] = `
class C extends E { foo: string; } // error
class D extends C { bar: string; }
class E extends D { baz: number; }
class C2<T> extends E2<T> { foo: T; } // error
class D2<T> extends C2<T> { bar: T; }
class E2<T> extends D2<T> { baz: T; }~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class C extends E {
foo: string;
} // error
class D extends C {
bar: string;
}
class E extends D {
baz: number;
}
class C2<T> extends E2<T> {
foo: T;
} // error
class D2<T> extends C2<T> {
bar: T;
}
class E2<T> extends D2<T> {
baz: T;
}
`;
exports[`classIsSubtypeOfBaseType.ts 1`] = `
class Base<T> {
foo: T;
}
class Derived extends Base<string> {
foo: any;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Base<T> {
foo: T;
}
class Derived extends Base<string> {
foo: any;
}
`;

View File

@ -0,0 +1,7 @@
class C { foo: string; }
var c: C;
var r = c.toString();
var r2 = c.hasOwnProperty('');
var o: Object = c;
var o2: {} = c;

View File

@ -0,0 +1,31 @@
class C {
foo: string;
thing() { }
static other() { }
}
class D extends C {
bar: string;
}
var d: D;
var r = d.foo;
var r2 = d.bar;
var r3 = d.thing();
var r4 = D.other();
class C2<T> {
foo: T;
thing(x: T) { }
static other<T>(x: T) { }
}
class D2<T> extends C2<T> {
bar: string;
}
var d2: D2<string>;
var r5 = d2.foo;
var r6 = d2.bar;
var r7 = d2.thing('');
var r8 = D2.other(1);

View File

@ -0,0 +1,11 @@
class C extends E { foo: string; } // error
class D extends C { bar: string; }
class E extends D { baz: number; }
class C2<T> extends E2<T> { foo: T; } // error
class D2<T> extends C2<T> { bar: T; }
class E2<T> extends D2<T> { baz: T; }

View File

@ -0,0 +1,7 @@
class Base<T> {
foo: T;
}
class Derived extends Base<string> {
foo: any;
}

View File

@ -0,0 +1 @@
run_spec(__dirname, { parser: "typescript" });

View File

@ -0,0 +1,3 @@
function foo() {
class C { }
}

View File

@ -0,0 +1 @@
run_spec(__dirname, { parser: "typescript" });

View File

@ -0,0 +1,10 @@
var x = class C {
}
var y = {
foo: class C2 {
}
}
var z = class C4 {
}

View File

@ -0,0 +1 @@
run_spec(__dirname, { parser: "typescript" });

View File

@ -0,0 +1,108 @@
// @declaration: true
type Constructable = new (...args: any[]) => object;
class Private {
constructor (...args: any[]) {}
private p: string;
}
class Private2 {
constructor (...args: any[]) {}
private p: string;
}
class Protected {
constructor (...args: any[]) {}
protected p: string;
protected static s: string;
}
class Protected2 {
constructor (...args: any[]) {}
protected p: string;
protected static s: string;
}
class Public {
constructor (...args: any[]) {}
public p: string;
public static s: string;
}
class Public2 {
constructor (...args: any[]) {}
public p: string;
public static s: string;
}
function f1(x: Private & Private2) {
x.p; // Error, private constituent makes property inaccessible
}
function f2(x: Private & Protected) {
x.p; // Error, private constituent makes property inaccessible
}
function f3(x: Private & Public) {
x.p; // Error, private constituent makes property inaccessible
}
function f4(x: Protected & Protected2) {
x.p; // Error, protected when all constituents are protected
}
function f5(x: Protected & Public) {
x.p; // Ok, public if any constituent is public
}
function f6(x: Public & Public2) {
x.p; // Ok, public if any constituent is public
}
declare function Mix<T, U>(c1: T, c2: U): T & U;
// Can't derive from type with inaccessible properties
class C1 extends Mix(Private, Private2) {}
class C2 extends Mix(Private, Protected) {}
class C3 extends Mix(Private, Public) {}
class C4 extends Mix(Protected, Protected2) {
f(c4: C4, c5: C5, c6: C6) {
c4.p;
c5.p;
c6.p;
}
static g() {
C4.s;
C5.s;
C6.s
}
}
class C5 extends Mix(Protected, Public) {
f(c4: C4, c5: C5, c6: C6) {
c4.p; // Error, not in class deriving from Protected2
c5.p;
c6.p;
}
static g() {
C4.s; // Error, not in class deriving from Protected2
C5.s;
C6.s
}
}
class C6 extends Mix(Public, Public2) {
f(c4: C4, c5: C5, c6: C6) {
c4.p; // Error, not in class deriving from Protected2
c5.p;
c6.p;
}
static g() {
C4.s; // Error, not in class deriving from Protected2
C5.s;
C6.s
}
}

View File

@ -0,0 +1,60 @@
// @declaration: true
type Constructor<T> = new(...args: any[]) => T;
class Base {
constructor(public x: number, public y: number) {}
}
class Derived extends Base {
constructor(x: number, y: number, public z: number) {
super(x, y);
}
}
const Printable = <T extends Constructor<Base>>(superClass: T): Constructor<Printable> & { message: string } & T =>
class extends superClass {
static message = "hello";
print() {
const output = this.x + "," + this.y;
}
}
function Tagged<T extends Constructor<{}>>(superClass: T): Constructor<Tagged> & T {
class C extends superClass {
_tag: string;
constructor(...args: any[]) {
super(...args);
this._tag = "hello";
}
}
return C;
}
const Thing1 = Tagged(Derived);
const Thing2 = Tagged(Printable(Derived));
Thing2.message;
function f1() {
const thing = new Thing1(1, 2, 3);
thing.x;
thing._tag;
}
function f2() {
const thing = new Thing2(1, 2, 3);
thing.x;
thing._tag;
thing.print();
}
class Thing3 extends Thing2 {
constructor(tag: string) {
super(10, 20, 30);
this._tag = tag;
}
test() {
this.print();
}
}

View File

@ -0,0 +1,64 @@
type Constructor<T> = new(...args: any[]) => T;
class Base {
constructor(public x: number, public y: number) {}
}
class Derived extends Base {
constructor(x: number, y: number, public z: number) {
super(x, y);
}
}
const Printable = <T extends Constructor<Base>>(superClass: T) => class extends superClass {
static message = "hello";
print() {
const output = this.x + "," + this.y;
}
}
function Tagged<T extends Constructor<{}>>(superClass: T) {
class C extends superClass {
_tag: string;
constructor(...args: any[]) {
super(...args);
this._tag = "hello";
}
}
return C;
}
const Thing1 = Tagged(Derived);
const Thing2 = Tagged(Printable(Derived));
Thing2.message;
function f1() {
const thing = new Thing1(1, 2, 3);
thing.x;
thing._tag;
}
function f2() {
const thing = new Thing2(1, 2, 3);
thing.x;
thing._tag;
thing.print();
}
class Thing3 extends Thing2 {
constructor(tag: string) {
super(10, 20, 30);
this._tag = tag;
}
test() {
this.print();
}
}
// Repro from #13805
const Timestamped = <CT extends Constructor<object>>(Base: CT) => {
return class extends Base {
timestamp = new Date();
};
}

View File

@ -0,0 +1,99 @@
// @declaration: true
declare class C1 {
public a: number;
protected b: number;
private c: number;
constructor(s: string);
constructor(n: number);
}
declare class M1 {
constructor(...args: any[]);
p: number;
static p: number;
}
declare class M2 {
constructor(...args: any[]);
f(): number;
static f(): number;
}
declare const Mixed1: typeof M1 & typeof C1;
declare const Mixed2: typeof C1 & typeof M1;
declare const Mixed3: typeof M2 & typeof M1 & typeof C1;
declare const Mixed4: typeof C1 & typeof M1 & typeof M2;
declare const Mixed5: typeof M1 & typeof M2;
function f1() {
let x1 = new Mixed1("hello");
let x2 = new Mixed1(42);
let x3 = new Mixed2("hello");
let x4 = new Mixed2(42);
let x5 = new Mixed3("hello");
let x6 = new Mixed3(42);
let x7 = new Mixed4("hello");
let x8 = new Mixed4(42);
let x9 = new Mixed5();
}
function f2() {
let x = new Mixed1("hello");
x.a;
x.p;
Mixed1.p;
}
function f3() {
let x = new Mixed2("hello");
x.a;
x.p;
Mixed2.p;
}
function f4() {
let x = new Mixed3("hello");
x.a;
x.p;
x.f();
Mixed3.p;
Mixed3.f();
}
function f5() {
let x = new Mixed4("hello");
x.a;
x.p;
x.f();
Mixed4.p;
Mixed4.f();
}
function f6() {
let x = new Mixed5();
x.p;
x.f();
Mixed5.p;
Mixed5.f();
}
class C2 extends Mixed1 {
constructor() {
super("hello");
this.a;
this.b;
this.p;
}
}
class C3 extends Mixed3 {
constructor() {
super(42);
this.a;
this.b;
this.p;
this.f();
}
f() { return super.f(); }
}

View File

@ -0,0 +1,10 @@
// nested classes are not allowed
class C {
x: string;
}
function foo() {
class C3 {
}
}

View File

@ -5,7 +5,7 @@ declare class MyArray<T> extends Array<T> {
sort(compareFn?: (a: T, b: T) => number): this;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
declare class MyArray<T> extends Array {
declare class MyArray<T> extends Array<T> {
sort(compareFn?: (a: T, b: T) => number): this;
}

View File

@ -104,7 +104,7 @@ class C2<T extends Date, U extends Date> {
// no errors expected
class C<T extends Date> {
g() {
g<T extends Number>() {
var x: T;
x.toFixed();
}
@ -116,7 +116,7 @@ class C<T extends Date> {
}
class C2<T extends Date, U extends Date> {
g() {
g<T extends Number, U extends Number>() {
var x: U;
x.toFixed();
}

View File

@ -30,3 +30,34 @@ let abstract;
export class Y {}
`;
exports[`abstractProperties.ts 1`] = `
abstract class Foo {
abstract private a: 1;
private abstract b: 2;
static abstract c: 3;
abstract private d = 4;
private abstract e = 5;
static abstract f = 6;
abstract private ['g'] = 4;
private abstract ['h'] = 5;
static abstract ['i'] = 6;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
abstract class Foo {
private abstract a: 1;
private abstract b: 2;
static abstract c: 3;
private abstract d = 4;
private abstract e = 5;
static abstract f = 6;
private abstract ["g"] = 4;
private abstract ["h"] = 5;
static abstract ["i"] = 6;
}
`;

View File

@ -0,0 +1,13 @@
abstract class Foo {
abstract private a: 1;
private abstract b: 2;
static abstract c: 3;
abstract private d = 4;
private abstract e = 5;
static abstract f = 6;
abstract private ['g'] = 4;
private abstract ['h'] = 5;
static abstract ['i'] = 6;
}