From f9e360d44b9f918bddc3a2b6ed1d52fdc0eaa4c7 Mon Sep 17 00:00:00 2001 From: Eli Barzilay Date: Mon, 17 Aug 2020 20:24:41 -0400 Subject: [PATCH] Add missing contextual type to static PropertyDeclarations Makes it possible to type class static fields. Fixes #33897. --- src/compiler/checker.ts | 12 +- ...ssExpressionMethodDeclaration01.errors.txt | 14 +- ...ClassExpressionMethodDeclaration01.symbols | 8 ++ ...edClassExpressionMethodDeclaration01.types | 48 +++---- .../staticFieldWithInterfaceContext.js | 106 +++++++++++++++ .../staticFieldWithInterfaceContext.symbols | 92 +++++++++++++ .../staticFieldWithInterfaceContext.types | 122 ++++++++++++++++++ .../staticFieldWithInterfaceContext.ts | 26 ++++ 8 files changed, 390 insertions(+), 38 deletions(-) create mode 100644 tests/baselines/reference/staticFieldWithInterfaceContext.js create mode 100644 tests/baselines/reference/staticFieldWithInterfaceContext.symbols create mode 100644 tests/baselines/reference/staticFieldWithInterfaceContext.types create mode 100644 tests/cases/compiler/staticFieldWithInterfaceContext.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bcf7c44cc31..f768bd29659 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22983,7 +22983,11 @@ namespace ts { return getContextuallyTypedParameterType(declaration); case SyntaxKind.BindingElement: return getContextualTypeForBindingElement(declaration); - // By default, do nothing and return undefined - only parameters and binding elements have context implied by a parent + case SyntaxKind.PropertyDeclaration: + if (hasSyntacticModifier(declaration, ModifierFlags.Static)) { + return getContextualTypeForStaticPropertyDeclaration(declaration); + } + // By default, do nothing and return undefined - only the above cases have context implied by a parent } } @@ -23001,6 +23005,12 @@ namespace ts { } } + function getContextualTypeForStaticPropertyDeclaration(declaration: PropertyDeclaration): Type | undefined { + const parentType = isExpression(declaration.parent) && getContextualType(declaration.parent); + if (!parentType) return undefined; + return getTypeOfPropertyOfContextualType(parentType, getSymbolOfNode(declaration).escapedName); + } + // In a variable, parameter or property declaration with a type annotation, // the contextual type of an initializer expression is the type of the variable, parameter or property. // Otherwise, in a parameter declaration of a contextually typed function expression, diff --git a/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.errors.txt b/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.errors.txt index 1fef4e61268..a99654c41f7 100644 --- a/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.errors.txt +++ b/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.errors.txt @@ -1,12 +1,8 @@ tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedClassExpressionMethodDeclaration01.ts(16,24): error TS7006: Parameter 'arg' implicitly has an 'any' type. tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedClassExpressionMethodDeclaration01.ts(19,24): error TS7006: Parameter 'arg' implicitly has an 'any' type. -tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedClassExpressionMethodDeclaration01.ts(27,27): error TS7006: Parameter 'arg' implicitly has an 'any' type. -tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedClassExpressionMethodDeclaration01.ts(30,27): error TS7006: Parameter 'arg' implicitly has an 'any' type. -tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedClassExpressionMethodDeclaration01.ts(38,36): error TS7006: Parameter 'arg' implicitly has an 'any' type. -tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedClassExpressionMethodDeclaration01.ts(41,36): error TS7006: Parameter 'arg' implicitly has an 'any' type. -==== tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedClassExpressionMethodDeclaration01.ts (6 errors) ==== +==== tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedClassExpressionMethodDeclaration01.ts (2 errors) ==== interface A { numProp: number; } @@ -38,13 +34,9 @@ tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTyp function getFoo2(): Foo { return class { static method1 = (arg) => { - ~~~ -!!! error TS7006: Parameter 'arg' implicitly has an 'any' type. arg.numProp = 10; } static method2 = (arg) => { - ~~~ -!!! error TS7006: Parameter 'arg' implicitly has an 'any' type. arg.strProp = "hello"; } } @@ -53,13 +45,9 @@ tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTyp function getFoo3(): Foo { return class { static method1 = function (arg) { - ~~~ -!!! error TS7006: Parameter 'arg' implicitly has an 'any' type. arg.numProp = 10; } static method2 = function (arg) { - ~~~ -!!! error TS7006: Parameter 'arg' implicitly has an 'any' type. arg.strProp = "hello"; } } diff --git a/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.symbols b/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.symbols index 0f3fca3824b..e305c38300c 100644 --- a/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.symbols +++ b/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.symbols @@ -59,14 +59,18 @@ function getFoo2(): Foo { >arg : Symbol(arg, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 26, 26)) arg.numProp = 10; +>arg.numProp : Symbol(A.numProp, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 0, 13)) >arg : Symbol(arg, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 26, 26)) +>numProp : Symbol(A.numProp, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 0, 13)) } static method2 = (arg) => { >method2 : Symbol((Anonymous class).method2, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 28, 9)) >arg : Symbol(arg, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 29, 26)) arg.strProp = "hello"; +>arg.strProp : Symbol(B.strProp, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 4, 14)) >arg : Symbol(arg, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 29, 26)) +>strProp : Symbol(B.strProp, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 4, 14)) } } } @@ -81,14 +85,18 @@ function getFoo3(): Foo { >arg : Symbol(arg, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 37, 35)) arg.numProp = 10; +>arg.numProp : Symbol(A.numProp, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 0, 13)) >arg : Symbol(arg, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 37, 35)) +>numProp : Symbol(A.numProp, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 0, 13)) } static method2 = function (arg) { >method2 : Symbol((Anonymous class).method2, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 39, 9)) >arg : Symbol(arg, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 40, 35)) arg.strProp = "hello"; +>arg.strProp : Symbol(B.strProp, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 4, 14)) >arg : Symbol(arg, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 40, 35)) +>strProp : Symbol(B.strProp, Decl(contextuallyTypedClassExpressionMethodDeclaration01.ts, 4, 14)) } } } diff --git a/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.types b/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.types index 3f321dcecb6..d3f439ca697 100644 --- a/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.types +++ b/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.types @@ -57,27 +57,27 @@ function getFoo2(): Foo { >class { static method1 = (arg) => { arg.numProp = 10; } static method2 = (arg) => { arg.strProp = "hello"; } } : typeof (Anonymous class) static method1 = (arg) => { ->method1 : (arg: any) => void ->(arg) => { arg.numProp = 10; } : (arg: any) => void ->arg : any +>method1 : (arg: A) => void +>(arg) => { arg.numProp = 10; } : (arg: A) => void +>arg : A arg.numProp = 10; >arg.numProp = 10 : 10 ->arg.numProp : any ->arg : any ->numProp : any +>arg.numProp : number +>arg : A +>numProp : number >10 : 10 } static method2 = (arg) => { ->method2 : (arg: any) => void ->(arg) => { arg.strProp = "hello"; } : (arg: any) => void ->arg : any +>method2 : (arg: B) => void +>(arg) => { arg.strProp = "hello"; } : (arg: B) => void +>arg : B arg.strProp = "hello"; >arg.strProp = "hello" : "hello" ->arg.strProp : any ->arg : any ->strProp : any +>arg.strProp : string +>arg : B +>strProp : string >"hello" : "hello" } } @@ -90,27 +90,27 @@ function getFoo3(): Foo { >class { static method1 = function (arg) { arg.numProp = 10; } static method2 = function (arg) { arg.strProp = "hello"; } } : typeof (Anonymous class) static method1 = function (arg) { ->method1 : (arg: any) => void ->function (arg) { arg.numProp = 10; } : (arg: any) => void ->arg : any +>method1 : (arg: A) => void +>function (arg) { arg.numProp = 10; } : (arg: A) => void +>arg : A arg.numProp = 10; >arg.numProp = 10 : 10 ->arg.numProp : any ->arg : any ->numProp : any +>arg.numProp : number +>arg : A +>numProp : number >10 : 10 } static method2 = function (arg) { ->method2 : (arg: any) => void ->function (arg) { arg.strProp = "hello"; } : (arg: any) => void ->arg : any +>method2 : (arg: B) => void +>function (arg) { arg.strProp = "hello"; } : (arg: B) => void +>arg : B arg.strProp = "hello"; >arg.strProp = "hello" : "hello" ->arg.strProp : any ->arg : any ->strProp : any +>arg.strProp : string +>arg : B +>strProp : string >"hello" : "hello" } } diff --git a/tests/baselines/reference/staticFieldWithInterfaceContext.js b/tests/baselines/reference/staticFieldWithInterfaceContext.js new file mode 100644 index 00000000000..0d372216049 --- /dev/null +++ b/tests/baselines/reference/staticFieldWithInterfaceContext.js @@ -0,0 +1,106 @@ +//// [staticFieldWithInterfaceContext.ts] +interface I { + x: { a: "a" }; +} +let c: I = class { + // should typecheck the same as the last line + static x = { a: "a" }; +}; +c.x = { a: "a" }; + +const ex = "x"; +let c2: I = class { static [ex] = { a: "a" }; }; +c[ex] = { a: "a" }; + +function f(c: I = class { static x = { a: "a" } }) { } + +let { c: c3 }: { c: I } = { c: class { static x = { a: "a" } } }; +let { c: c4 = class { static x = { a: "a" } }}: { c?: I } = { }; +let { c: c5 = class { static x = { a: "a" } }}: { c?: I } = { c: class { static x = { a: "a" } } }; +let [ c6 ]: [I] = [class { static x = { a: "a" } }]; +let [ c7 ]: I[] = [class { static x = { a: "a" } }]; + +// These are broken because of #40158 +// let [ c8 = class { static x = { a: "a" } } ]: [I?] = []; +// let [ c9 = class { static x = { a: "a" } } ]: I[] = []; +// let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }]; +// let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }]; + + +//// [staticFieldWithInterfaceContext.js] +var _a, _b, _c, _d, _e, _f, _g, _h, _j; +var c = (_a = /** @class */ (function () { + function class_1() { + } + return class_1; + }()), + // should typecheck the same as the last line + _a.x = { a: "a" }, + _a); +c.x = { a: "a" }; +var ex = "x"; +var c2 = (_c = /** @class */ (function () { + function class_2() { + } + return class_2; + }()), + _b = ex, + _c[_b] = { a: "a" }, + _c); +c[ex] = { a: "a" }; +function f(c) { + var _a; + if (c === void 0) { c = (_a = /** @class */ (function () { + function class_3() { + } + return class_3; + }()), + _a.x = { a: "a" }, + _a); } +} +var c3 = { c: (_d = /** @class */ (function () { + function class_4() { + } + return class_4; + }()), + _d.x = { a: "a" }, + _d) }.c; +var _k = {}.c, c4 = _k === void 0 ? (_e = /** @class */ (function () { + function class_5() { + } + return class_5; + }()), + _e.x = { a: "a" }, + _e) : _k; +var _l = { c: (_g = /** @class */ (function () { + function class_6() { + } + return class_6; + }()), + _g.x = { a: "a" }, + _g) }.c, c5 = _l === void 0 ? (_f = /** @class */ (function () { + function class_7() { + } + return class_7; + }()), + _f.x = { a: "a" }, + _f) : _l; +var c6 = [(_h = /** @class */ (function () { + function class_8() { + } + return class_8; + }()), + _h.x = { a: "a" }, + _h)][0]; +var c7 = [(_j = /** @class */ (function () { + function class_9() { + } + return class_9; + }()), + _j.x = { a: "a" }, + _j)][0]; +// These are broken because of #40158 +// let [ c8 = class { static x = { a: "a" } } ]: [I?] = []; +// let [ c9 = class { static x = { a: "a" } } ]: I[] = []; +// let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }]; +// let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }]; diff --git a/tests/baselines/reference/staticFieldWithInterfaceContext.symbols b/tests/baselines/reference/staticFieldWithInterfaceContext.symbols new file mode 100644 index 00000000000..2bce524f2de --- /dev/null +++ b/tests/baselines/reference/staticFieldWithInterfaceContext.symbols @@ -0,0 +1,92 @@ +=== tests/cases/compiler/staticFieldWithInterfaceContext.ts === +interface I { +>I : Symbol(I, Decl(staticFieldWithInterfaceContext.ts, 0, 0)) + + x: { a: "a" }; +>x : Symbol(I.x, Decl(staticFieldWithInterfaceContext.ts, 0, 13)) +>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 1, 8)) +} +let c: I = class { +>c : Symbol(c, Decl(staticFieldWithInterfaceContext.ts, 3, 3)) +>I : Symbol(I, Decl(staticFieldWithInterfaceContext.ts, 0, 0)) + + // should typecheck the same as the last line + static x = { a: "a" }; +>x : Symbol(c.x, Decl(staticFieldWithInterfaceContext.ts, 3, 18)) +>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 5, 16)) + +}; +c.x = { a: "a" }; +>c.x : Symbol(I.x, Decl(staticFieldWithInterfaceContext.ts, 0, 13)) +>c : Symbol(c, Decl(staticFieldWithInterfaceContext.ts, 3, 3)) +>x : Symbol(I.x, Decl(staticFieldWithInterfaceContext.ts, 0, 13)) +>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 7, 7)) + +const ex = "x"; +>ex : Symbol(ex, Decl(staticFieldWithInterfaceContext.ts, 9, 5)) + +let c2: I = class { static [ex] = { a: "a" }; }; +>c2 : Symbol(c2, Decl(staticFieldWithInterfaceContext.ts, 10, 3)) +>I : Symbol(I, Decl(staticFieldWithInterfaceContext.ts, 0, 0)) +>[ex] : Symbol(c2[ex], Decl(staticFieldWithInterfaceContext.ts, 10, 19)) +>ex : Symbol(ex, Decl(staticFieldWithInterfaceContext.ts, 9, 5)) +>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 10, 35)) + +c[ex] = { a: "a" }; +>c : Symbol(c, Decl(staticFieldWithInterfaceContext.ts, 3, 3)) +>ex : Symbol(ex, Decl(staticFieldWithInterfaceContext.ts, 9, 5)) +>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 11, 9)) + +function f(c: I = class { static x = { a: "a" } }) { } +>f : Symbol(f, Decl(staticFieldWithInterfaceContext.ts, 11, 19)) +>c : Symbol(c, Decl(staticFieldWithInterfaceContext.ts, 13, 11)) +>I : Symbol(I, Decl(staticFieldWithInterfaceContext.ts, 0, 0)) +>x : Symbol((Anonymous class).x, Decl(staticFieldWithInterfaceContext.ts, 13, 25)) +>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 13, 38)) + +let { c: c3 }: { c: I } = { c: class { static x = { a: "a" } } }; +>c : Symbol(c, Decl(staticFieldWithInterfaceContext.ts, 15, 16)) +>c3 : Symbol(c3, Decl(staticFieldWithInterfaceContext.ts, 15, 5)) +>c : Symbol(c, Decl(staticFieldWithInterfaceContext.ts, 15, 16)) +>I : Symbol(I, Decl(staticFieldWithInterfaceContext.ts, 0, 0)) +>c : Symbol(c, Decl(staticFieldWithInterfaceContext.ts, 15, 27)) +>x : Symbol(c.x, Decl(staticFieldWithInterfaceContext.ts, 15, 38)) +>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 15, 51)) + +let { c: c4 = class { static x = { a: "a" } }}: { c?: I } = { }; +>c : Symbol(c, Decl(staticFieldWithInterfaceContext.ts, 16, 49)) +>c4 : Symbol(c4, Decl(staticFieldWithInterfaceContext.ts, 16, 5)) +>x : Symbol(c4.x, Decl(staticFieldWithInterfaceContext.ts, 16, 21)) +>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 16, 34)) +>c : Symbol(c, Decl(staticFieldWithInterfaceContext.ts, 16, 49)) +>I : Symbol(I, Decl(staticFieldWithInterfaceContext.ts, 0, 0)) + +let { c: c5 = class { static x = { a: "a" } }}: { c?: I } = { c: class { static x = { a: "a" } } }; +>c : Symbol(c, Decl(staticFieldWithInterfaceContext.ts, 17, 49)) +>c5 : Symbol(c5, Decl(staticFieldWithInterfaceContext.ts, 17, 5)) +>x : Symbol(c5.x, Decl(staticFieldWithInterfaceContext.ts, 17, 21)) +>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 17, 34)) +>c : Symbol(c, Decl(staticFieldWithInterfaceContext.ts, 17, 49)) +>I : Symbol(I, Decl(staticFieldWithInterfaceContext.ts, 0, 0)) +>c : Symbol(c, Decl(staticFieldWithInterfaceContext.ts, 17, 61)) +>x : Symbol(c.x, Decl(staticFieldWithInterfaceContext.ts, 17, 72)) +>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 17, 85)) + +let [ c6 ]: [I] = [class { static x = { a: "a" } }]; +>c6 : Symbol(c6, Decl(staticFieldWithInterfaceContext.ts, 18, 5)) +>I : Symbol(I, Decl(staticFieldWithInterfaceContext.ts, 0, 0)) +>x : Symbol((Anonymous class).x, Decl(staticFieldWithInterfaceContext.ts, 18, 26)) +>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 18, 39)) + +let [ c7 ]: I[] = [class { static x = { a: "a" } }]; +>c7 : Symbol(c7, Decl(staticFieldWithInterfaceContext.ts, 19, 5)) +>I : Symbol(I, Decl(staticFieldWithInterfaceContext.ts, 0, 0)) +>x : Symbol((Anonymous class).x, Decl(staticFieldWithInterfaceContext.ts, 19, 26)) +>a : Symbol(a, Decl(staticFieldWithInterfaceContext.ts, 19, 39)) + +// These are broken because of #40158 +// let [ c8 = class { static x = { a: "a" } } ]: [I?] = []; +// let [ c9 = class { static x = { a: "a" } } ]: I[] = []; +// let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }]; +// let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }]; + diff --git a/tests/baselines/reference/staticFieldWithInterfaceContext.types b/tests/baselines/reference/staticFieldWithInterfaceContext.types new file mode 100644 index 00000000000..d0c5e94a514 --- /dev/null +++ b/tests/baselines/reference/staticFieldWithInterfaceContext.types @@ -0,0 +1,122 @@ +=== tests/cases/compiler/staticFieldWithInterfaceContext.ts === +interface I { + x: { a: "a" }; +>x : { a: "a"; } +>a : "a" +} +let c: I = class { +>c : I +>class { // should typecheck the same as the last line static x = { a: "a" };} : typeof c + + // should typecheck the same as the last line + static x = { a: "a" }; +>x : { a: "a"; } +>{ a: "a" } : { a: "a"; } +>a : "a" +>"a" : "a" + +}; +c.x = { a: "a" }; +>c.x = { a: "a" } : { a: "a"; } +>c.x : { a: "a"; } +>c : I +>x : { a: "a"; } +>{ a: "a" } : { a: "a"; } +>a : "a" +>"a" : "a" + +const ex = "x"; +>ex : "x" +>"x" : "x" + +let c2: I = class { static [ex] = { a: "a" }; }; +>c2 : I +>class { static [ex] = { a: "a" }; } : typeof c2 +>[ex] : { a: "a"; } +>ex : "x" +>{ a: "a" } : { a: "a"; } +>a : "a" +>"a" : "a" + +c[ex] = { a: "a" }; +>c[ex] = { a: "a" } : { a: "a"; } +>c[ex] : { a: "a"; } +>c : I +>ex : "x" +>{ a: "a" } : { a: "a"; } +>a : "a" +>"a" : "a" + +function f(c: I = class { static x = { a: "a" } }) { } +>f : (c?: I) => void +>c : I +>class { static x = { a: "a" } } : typeof (Anonymous class) +>x : { a: "a"; } +>{ a: "a" } : { a: "a"; } +>a : "a" +>"a" : "a" + +let { c: c3 }: { c: I } = { c: class { static x = { a: "a" } } }; +>c : any +>c3 : I +>c : I +>{ c: class { static x = { a: "a" } } } : { c: typeof c; } +>c : typeof c +>class { static x = { a: "a" } } : typeof c +>x : { a: "a"; } +>{ a: "a" } : { a: "a"; } +>a : "a" +>"a" : "a" + +let { c: c4 = class { static x = { a: "a" } }}: { c?: I } = { }; +>c : any +>c4 : I +>class { static x = { a: "a" } } : typeof c4 +>x : { a: "a"; } +>{ a: "a" } : { a: "a"; } +>a : "a" +>"a" : "a" +>c : I +>{ } : {} + +let { c: c5 = class { static x = { a: "a" } }}: { c?: I } = { c: class { static x = { a: "a" } } }; +>c : any +>c5 : I +>class { static x = { a: "a" } } : typeof c5 +>x : { a: "a"; } +>{ a: "a" } : { a: "a"; } +>a : "a" +>"a" : "a" +>c : I +>{ c: class { static x = { a: "a" } } } : { c: typeof c; } +>c : typeof c +>class { static x = { a: "a" } } : typeof c +>x : { a: "a"; } +>{ a: "a" } : { a: "a"; } +>a : "a" +>"a" : "a" + +let [ c6 ]: [I] = [class { static x = { a: "a" } }]; +>c6 : I +>[class { static x = { a: "a" } }] : [typeof (Anonymous class)] +>class { static x = { a: "a" } } : typeof (Anonymous class) +>x : { a: "a"; } +>{ a: "a" } : { a: "a"; } +>a : "a" +>"a" : "a" + +let [ c7 ]: I[] = [class { static x = { a: "a" } }]; +>c7 : I +>[class { static x = { a: "a" } }] : (typeof (Anonymous class))[] +>class { static x = { a: "a" } } : typeof (Anonymous class) +>x : { a: "a"; } +>{ a: "a" } : { a: "a"; } +>a : "a" +>"a" : "a" + +// These are broken because of #40158 +// let [ c8 = class { static x = { a: "a" } } ]: [I?] = []; +// let [ c9 = class { static x = { a: "a" } } ]: I[] = []; +// let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }]; +// let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }]; + diff --git a/tests/cases/compiler/staticFieldWithInterfaceContext.ts b/tests/cases/compiler/staticFieldWithInterfaceContext.ts new file mode 100644 index 00000000000..e89640db7d7 --- /dev/null +++ b/tests/cases/compiler/staticFieldWithInterfaceContext.ts @@ -0,0 +1,26 @@ +interface I { + x: { a: "a" }; +} +let c: I = class { + // should typecheck the same as the last line + static x = { a: "a" }; +}; +c.x = { a: "a" }; + +const ex = "x"; +let c2: I = class { static [ex] = { a: "a" }; }; +c[ex] = { a: "a" }; + +function f(c: I = class { static x = { a: "a" } }) { } + +let { c: c3 }: { c: I } = { c: class { static x = { a: "a" } } }; +let { c: c4 = class { static x = { a: "a" } }}: { c?: I } = { }; +let { c: c5 = class { static x = { a: "a" } }}: { c?: I } = { c: class { static x = { a: "a" } } }; +let [ c6 ]: [I] = [class { static x = { a: "a" } }]; +let [ c7 ]: I[] = [class { static x = { a: "a" } }]; + +// These are broken because of #40158 +// let [ c8 = class { static x = { a: "a" } } ]: [I?] = []; +// let [ c9 = class { static x = { a: "a" } } ]: I[] = []; +// let [ c10 = class { static x = { a: "a" } } ]: [I?] = [class { static x = { a: "a" } }]; +// let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a" } }];