mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Contextual signatures without thisType return anyType
If a contextual signature is found, if its thisType is undefined, then the contextual type of `this` is now `any`. Previously `checkThisExpression` would keep looking for a different type for `this`. Also update tests to show this new behaviour.
This commit is contained in:
@@ -8453,7 +8453,7 @@ namespace ts {
|
||||
if (isContextSensitiveFunctionOrObjectLiteralMethod(func) && func.kind !== SyntaxKind.ArrowFunction) {
|
||||
const contextualSignature = getContextualSignature(func);
|
||||
if (contextualSignature) {
|
||||
return contextualSignature.thisType;
|
||||
return contextualSignature.thisType || anyType;
|
||||
}
|
||||
else if (getContextualTypeForFunctionLikeDeclaration(func) === anyType) {
|
||||
return anyType;
|
||||
|
||||
@@ -1,51 +1,91 @@
|
||||
//// [thisTypeInFunctions2.ts]
|
||||
interface Arguments {
|
||||
init?: (this: void) => void;
|
||||
interface IndexedWithThis {
|
||||
// this is a workaround for React
|
||||
init?: (this: this) => void;
|
||||
willDestroy?: (this: any) => void;
|
||||
[propName: string]: number | string | boolean | symbol | undefined | null | {} | ((this: any, ...args:any[]) => any);
|
||||
}
|
||||
declare function extend(arguments: Arguments): void;
|
||||
class Mixin {
|
||||
stuff: number;
|
||||
interface IndexedWithoutThis {
|
||||
// this is what React would like to write (and what they write today)
|
||||
init?: () => void;
|
||||
willDestroy?: () => void;
|
||||
[propName: string]: any;
|
||||
}
|
||||
interface SimpleInterface {
|
||||
foo(n: string);
|
||||
bar(): number;
|
||||
}
|
||||
declare function extend1(args: IndexedWithThis): void;
|
||||
declare function extend2(args: IndexedWithoutThis): void;
|
||||
declare function simple(arg: SimpleInterface): void;
|
||||
|
||||
extend({
|
||||
extend1({
|
||||
init() {
|
||||
this
|
||||
this // this: IndexedWithThis because of contextual typing.
|
||||
// this.mine
|
||||
this.willDestroy
|
||||
},
|
||||
mine: 12,
|
||||
bar() {
|
||||
this.init();
|
||||
},
|
||||
foo() {
|
||||
this.bar;
|
||||
this.url
|
||||
this.handler()
|
||||
this.baz
|
||||
this.url; // this: any because 'foo' matches the string indexer
|
||||
this.willDestroy;
|
||||
}
|
||||
});
|
||||
extend2({
|
||||
init() {
|
||||
this // this: any because the contextual signature of init doesn't specify this' type
|
||||
this.mine
|
||||
this.willDestroy
|
||||
},
|
||||
mine: 13,
|
||||
foo() {
|
||||
this // this: any because of the string indexer
|
||||
this.mine
|
||||
this.willDestroy
|
||||
}
|
||||
});
|
||||
|
||||
simple({
|
||||
foo(n) {
|
||||
return n.length + this.bar();
|
||||
},
|
||||
bar() {
|
||||
return 14;
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
//// [thisTypeInFunctions2.js]
|
||||
var Mixin = (function () {
|
||||
function Mixin() {
|
||||
}
|
||||
return Mixin;
|
||||
}());
|
||||
extend({
|
||||
extend1({
|
||||
init: function () {
|
||||
this;
|
||||
this; // this: IndexedWithThis because of contextual typing.
|
||||
// this.mine
|
||||
this.willDestroy;
|
||||
},
|
||||
mine: 12,
|
||||
bar: function () {
|
||||
this.init();
|
||||
},
|
||||
foo: function () {
|
||||
this.bar;
|
||||
this.url;
|
||||
this.handler();
|
||||
this.baz;
|
||||
this.url; // this: any because 'foo' matches the string indexer
|
||||
this.willDestroy;
|
||||
}
|
||||
});
|
||||
extend2({
|
||||
init: function () {
|
||||
this; // this: any because the contextual signature of init doesn't specify this' type
|
||||
this.mine;
|
||||
this.willDestroy;
|
||||
},
|
||||
mine: 13,
|
||||
foo: function () {
|
||||
this; // this: any because of the string indexer
|
||||
this.mine;
|
||||
this.willDestroy;
|
||||
}
|
||||
});
|
||||
simple({
|
||||
foo: function (n) {
|
||||
return n.length + this.bar();
|
||||
},
|
||||
bar: function () {
|
||||
return 14;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,56 +1,124 @@
|
||||
=== tests/cases/conformance/types/thisType/thisTypeInFunctions2.ts ===
|
||||
interface Arguments {
|
||||
>Arguments : Symbol(Arguments, Decl(thisTypeInFunctions2.ts, 0, 0))
|
||||
interface IndexedWithThis {
|
||||
>IndexedWithThis : Symbol(IndexedWithThis, Decl(thisTypeInFunctions2.ts, 0, 0))
|
||||
|
||||
init?: (this: void) => void;
|
||||
>init : Symbol(Arguments.init, Decl(thisTypeInFunctions2.ts, 0, 21))
|
||||
>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 1, 12))
|
||||
// this is a workaround for React
|
||||
init?: (this: this) => void;
|
||||
>init : Symbol(IndexedWithThis.init, Decl(thisTypeInFunctions2.ts, 0, 27))
|
||||
>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 2, 12))
|
||||
|
||||
willDestroy?: (this: any) => void;
|
||||
>willDestroy : Symbol(Arguments.willDestroy, Decl(thisTypeInFunctions2.ts, 1, 32))
|
||||
>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 2, 19))
|
||||
>willDestroy : Symbol(IndexedWithThis.willDestroy, Decl(thisTypeInFunctions2.ts, 2, 32))
|
||||
>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 3, 19))
|
||||
|
||||
[propName: string]: number | string | boolean | symbol | undefined | null | {} | ((this: any, ...args:any[]) => any);
|
||||
>propName : Symbol(propName, Decl(thisTypeInFunctions2.ts, 3, 5))
|
||||
>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 3, 87))
|
||||
>args : Symbol(args, Decl(thisTypeInFunctions2.ts, 3, 97))
|
||||
>propName : Symbol(propName, Decl(thisTypeInFunctions2.ts, 4, 5))
|
||||
>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 4, 87))
|
||||
>args : Symbol(args, Decl(thisTypeInFunctions2.ts, 4, 97))
|
||||
}
|
||||
declare function extend(arguments: Arguments): void;
|
||||
>extend : Symbol(extend, Decl(thisTypeInFunctions2.ts, 4, 1))
|
||||
>arguments : Symbol(arguments, Decl(thisTypeInFunctions2.ts, 5, 24))
|
||||
>Arguments : Symbol(Arguments, Decl(thisTypeInFunctions2.ts, 0, 0))
|
||||
interface IndexedWithoutThis {
|
||||
>IndexedWithoutThis : Symbol(IndexedWithoutThis, Decl(thisTypeInFunctions2.ts, 5, 1))
|
||||
|
||||
class Mixin {
|
||||
>Mixin : Symbol(Mixin, Decl(thisTypeInFunctions2.ts, 5, 52))
|
||||
// this is what React would like to write (and what they write today)
|
||||
init?: () => void;
|
||||
>init : Symbol(IndexedWithoutThis.init, Decl(thisTypeInFunctions2.ts, 6, 30))
|
||||
|
||||
stuff: number;
|
||||
>stuff : Symbol(Mixin.stuff, Decl(thisTypeInFunctions2.ts, 6, 13))
|
||||
willDestroy?: () => void;
|
||||
>willDestroy : Symbol(IndexedWithoutThis.willDestroy, Decl(thisTypeInFunctions2.ts, 8, 22))
|
||||
|
||||
[propName: string]: any;
|
||||
>propName : Symbol(propName, Decl(thisTypeInFunctions2.ts, 10, 5))
|
||||
}
|
||||
interface SimpleInterface {
|
||||
>SimpleInterface : Symbol(SimpleInterface, Decl(thisTypeInFunctions2.ts, 11, 1))
|
||||
|
||||
extend({
|
||||
>extend : Symbol(extend, Decl(thisTypeInFunctions2.ts, 4, 1))
|
||||
foo(n: string);
|
||||
>foo : Symbol(SimpleInterface.foo, Decl(thisTypeInFunctions2.ts, 12, 27))
|
||||
>n : Symbol(n, Decl(thisTypeInFunctions2.ts, 13, 8))
|
||||
|
||||
bar(): number;
|
||||
>bar : Symbol(SimpleInterface.bar, Decl(thisTypeInFunctions2.ts, 13, 19))
|
||||
}
|
||||
declare function extend1(args: IndexedWithThis): void;
|
||||
>extend1 : Symbol(extend1, Decl(thisTypeInFunctions2.ts, 15, 1))
|
||||
>args : Symbol(args, Decl(thisTypeInFunctions2.ts, 16, 25))
|
||||
>IndexedWithThis : Symbol(IndexedWithThis, Decl(thisTypeInFunctions2.ts, 0, 0))
|
||||
|
||||
declare function extend2(args: IndexedWithoutThis): void;
|
||||
>extend2 : Symbol(extend2, Decl(thisTypeInFunctions2.ts, 16, 54))
|
||||
>args : Symbol(args, Decl(thisTypeInFunctions2.ts, 17, 25))
|
||||
>IndexedWithoutThis : Symbol(IndexedWithoutThis, Decl(thisTypeInFunctions2.ts, 5, 1))
|
||||
|
||||
declare function simple(arg: SimpleInterface): void;
|
||||
>simple : Symbol(simple, Decl(thisTypeInFunctions2.ts, 17, 57))
|
||||
>arg : Symbol(arg, Decl(thisTypeInFunctions2.ts, 18, 24))
|
||||
>SimpleInterface : Symbol(SimpleInterface, Decl(thisTypeInFunctions2.ts, 11, 1))
|
||||
|
||||
extend1({
|
||||
>extend1 : Symbol(extend1, Decl(thisTypeInFunctions2.ts, 15, 1))
|
||||
|
||||
init() {
|
||||
>init : Symbol(init, Decl(thisTypeInFunctions2.ts, 10, 8))
|
||||
>init : Symbol(init, Decl(thisTypeInFunctions2.ts, 20, 9))
|
||||
|
||||
this // this: IndexedWithThis because of contextual typing.
|
||||
>this : Symbol(IndexedWithThis, Decl(thisTypeInFunctions2.ts, 0, 0))
|
||||
|
||||
// this.mine
|
||||
this.willDestroy
|
||||
>this.willDestroy : Symbol(IndexedWithThis.willDestroy, Decl(thisTypeInFunctions2.ts, 2, 32))
|
||||
>this : Symbol(IndexedWithThis, Decl(thisTypeInFunctions2.ts, 0, 0))
|
||||
>willDestroy : Symbol(IndexedWithThis.willDestroy, Decl(thisTypeInFunctions2.ts, 2, 32))
|
||||
|
||||
this
|
||||
},
|
||||
mine: 12,
|
||||
>mine : Symbol(mine, Decl(thisTypeInFunctions2.ts, 13, 6))
|
||||
>mine : Symbol(mine, Decl(thisTypeInFunctions2.ts, 25, 6))
|
||||
|
||||
bar() {
|
||||
>bar : Symbol(bar, Decl(thisTypeInFunctions2.ts, 14, 13))
|
||||
|
||||
this.init();
|
||||
},
|
||||
foo() {
|
||||
>foo : Symbol(foo, Decl(thisTypeInFunctions2.ts, 17, 6))
|
||||
>foo : Symbol(foo, Decl(thisTypeInFunctions2.ts, 26, 13))
|
||||
|
||||
this.bar;
|
||||
this.url
|
||||
this.handler()
|
||||
this.baz
|
||||
this.url; // this: any because 'foo' matches the string indexer
|
||||
this.willDestroy;
|
||||
}
|
||||
});
|
||||
extend2({
|
||||
>extend2 : Symbol(extend2, Decl(thisTypeInFunctions2.ts, 16, 54))
|
||||
|
||||
init() {
|
||||
>init : Symbol(init, Decl(thisTypeInFunctions2.ts, 32, 9))
|
||||
|
||||
this // this: any because the contextual signature of init doesn't specify this' type
|
||||
this.mine
|
||||
this.willDestroy
|
||||
},
|
||||
mine: 13,
|
||||
>mine : Symbol(mine, Decl(thisTypeInFunctions2.ts, 37, 6))
|
||||
|
||||
foo() {
|
||||
>foo : Symbol(foo, Decl(thisTypeInFunctions2.ts, 38, 13))
|
||||
|
||||
this // this: any because of the string indexer
|
||||
this.mine
|
||||
this.willDestroy
|
||||
}
|
||||
});
|
||||
|
||||
simple({
|
||||
>simple : Symbol(simple, Decl(thisTypeInFunctions2.ts, 17, 57))
|
||||
|
||||
foo(n) {
|
||||
>foo : Symbol(foo, Decl(thisTypeInFunctions2.ts, 46, 8))
|
||||
>n : Symbol(n, Decl(thisTypeInFunctions2.ts, 47, 8))
|
||||
|
||||
return n.length + this.bar();
|
||||
>n.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>n : Symbol(n, Decl(thisTypeInFunctions2.ts, 47, 8))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
|
||||
},
|
||||
bar() {
|
||||
>bar : Symbol(bar, Decl(thisTypeInFunctions2.ts, 49, 6))
|
||||
|
||||
return 14;
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
=== tests/cases/conformance/types/thisType/thisTypeInFunctions2.ts ===
|
||||
interface Arguments {
|
||||
>Arguments : Arguments
|
||||
interface IndexedWithThis {
|
||||
>IndexedWithThis : IndexedWithThis
|
||||
|
||||
init?: (this: void) => void;
|
||||
>init : (this: void) => void
|
||||
>this : void
|
||||
// this is a workaround for React
|
||||
init?: (this: this) => void;
|
||||
>init : (this: this) => void
|
||||
>this : this
|
||||
|
||||
willDestroy?: (this: any) => void;
|
||||
>willDestroy : (this: any) => void
|
||||
@@ -16,72 +17,149 @@ interface Arguments {
|
||||
>this : any
|
||||
>args : any[]
|
||||
}
|
||||
declare function extend(arguments: Arguments): void;
|
||||
>extend : (arguments: Arguments) => void
|
||||
>arguments : Arguments
|
||||
>Arguments : Arguments
|
||||
interface IndexedWithoutThis {
|
||||
>IndexedWithoutThis : IndexedWithoutThis
|
||||
|
||||
class Mixin {
|
||||
>Mixin : Mixin
|
||||
// this is what React would like to write (and what they write today)
|
||||
init?: () => void;
|
||||
>init : () => void
|
||||
|
||||
stuff: number;
|
||||
>stuff : number
|
||||
willDestroy?: () => void;
|
||||
>willDestroy : () => void
|
||||
|
||||
[propName: string]: any;
|
||||
>propName : string
|
||||
}
|
||||
interface SimpleInterface {
|
||||
>SimpleInterface : SimpleInterface
|
||||
|
||||
extend({
|
||||
>extend({ init() { this }, mine: 12, bar() { this.init(); }, foo() { this.bar; this.url this.handler() this.baz this.willDestroy }}) : void
|
||||
>extend : (arguments: Arguments) => void
|
||||
>{ init() { this }, mine: 12, bar() { this.init(); }, foo() { this.bar; this.url this.handler() this.baz this.willDestroy }} : { init(): void; mine: number; bar(): void; foo(): void; }
|
||||
foo(n: string);
|
||||
>foo : (n: string) => any
|
||||
>n : string
|
||||
|
||||
bar(): number;
|
||||
>bar : () => number
|
||||
}
|
||||
declare function extend1(args: IndexedWithThis): void;
|
||||
>extend1 : (args: IndexedWithThis) => void
|
||||
>args : IndexedWithThis
|
||||
>IndexedWithThis : IndexedWithThis
|
||||
|
||||
declare function extend2(args: IndexedWithoutThis): void;
|
||||
>extend2 : (args: IndexedWithoutThis) => void
|
||||
>args : IndexedWithoutThis
|
||||
>IndexedWithoutThis : IndexedWithoutThis
|
||||
|
||||
declare function simple(arg: SimpleInterface): void;
|
||||
>simple : (arg: SimpleInterface) => void
|
||||
>arg : SimpleInterface
|
||||
>SimpleInterface : SimpleInterface
|
||||
|
||||
extend1({
|
||||
>extend1({ init() { this // this: IndexedWithThis because of contextual typing. // this.mine this.willDestroy }, mine: 12, foo() { this.url; // this: any because 'foo' matches the string indexer this.willDestroy; }}) : void
|
||||
>extend1 : (args: IndexedWithThis) => void
|
||||
>{ init() { this // this: IndexedWithThis because of contextual typing. // this.mine this.willDestroy }, mine: 12, foo() { this.url; // this: any because 'foo' matches the string indexer this.willDestroy; }} : { init(): void; mine: number; foo(): void; }
|
||||
|
||||
init() {
|
||||
>init : () => void
|
||||
|
||||
this
|
||||
>this : void
|
||||
this // this: IndexedWithThis because of contextual typing.
|
||||
>this : IndexedWithThis
|
||||
|
||||
// this.mine
|
||||
this.willDestroy
|
||||
>this.willDestroy : (this: any) => void
|
||||
>this : IndexedWithThis
|
||||
>willDestroy : (this: any) => void
|
||||
|
||||
},
|
||||
mine: 12,
|
||||
>mine : number
|
||||
>12 : number
|
||||
|
||||
bar() {
|
||||
>bar : () => void
|
||||
|
||||
this.init();
|
||||
>this.init() : any
|
||||
>this.init : any
|
||||
>this : any
|
||||
>init : any
|
||||
|
||||
},
|
||||
foo() {
|
||||
>foo : () => void
|
||||
|
||||
this.bar;
|
||||
>this.bar : any
|
||||
>this : any
|
||||
>bar : any
|
||||
|
||||
this.url
|
||||
this.url; // this: any because 'foo' matches the string indexer
|
||||
>this.url : any
|
||||
>this : any
|
||||
>url : any
|
||||
|
||||
this.handler()
|
||||
>this.handler() : any
|
||||
>this.handler : any
|
||||
this.willDestroy;
|
||||
>this.willDestroy : any
|
||||
>this : any
|
||||
>handler : any
|
||||
>willDestroy : any
|
||||
}
|
||||
});
|
||||
extend2({
|
||||
>extend2({ init() { this // this: any because the contextual signature of init doesn't specify this' type this.mine this.willDestroy }, mine: 13, foo() { this // this: any because of the string indexer this.mine this.willDestroy }}) : void
|
||||
>extend2 : (args: IndexedWithoutThis) => void
|
||||
>{ init() { this // this: any because the contextual signature of init doesn't specify this' type this.mine this.willDestroy }, mine: 13, foo() { this // this: any because of the string indexer this.mine this.willDestroy }} : { init(): void; mine: number; foo(): void; }
|
||||
|
||||
this.baz
|
||||
>this.baz : any
|
||||
init() {
|
||||
>init : () => void
|
||||
|
||||
this // this: any because the contextual signature of init doesn't specify this' type
|
||||
>this : any
|
||||
>baz : any
|
||||
|
||||
this.mine
|
||||
>this.mine : any
|
||||
>this : any
|
||||
>mine : any
|
||||
|
||||
this.willDestroy
|
||||
>this.willDestroy : any
|
||||
>this : any
|
||||
>willDestroy : any
|
||||
|
||||
},
|
||||
mine: 13,
|
||||
>mine : number
|
||||
>13 : number
|
||||
|
||||
foo() {
|
||||
>foo : () => void
|
||||
|
||||
this // this: any because of the string indexer
|
||||
>this : any
|
||||
|
||||
this.mine
|
||||
>this.mine : any
|
||||
>this : any
|
||||
>mine : any
|
||||
|
||||
this.willDestroy
|
||||
>this.willDestroy : any
|
||||
>this : any
|
||||
>willDestroy : any
|
||||
}
|
||||
});
|
||||
|
||||
simple({
|
||||
>simple({ foo(n) { return n.length + this.bar(); }, bar() { return 14; }}) : void
|
||||
>simple : (arg: SimpleInterface) => void
|
||||
>{ foo(n) { return n.length + this.bar(); }, bar() { return 14; }} : { foo(n: string): any; bar(): number; }
|
||||
|
||||
foo(n) {
|
||||
>foo : (n: string) => any
|
||||
>n : string
|
||||
|
||||
return n.length + this.bar();
|
||||
>n.length + this.bar() : any
|
||||
>n.length : number
|
||||
>n : string
|
||||
>length : number
|
||||
>this.bar() : any
|
||||
>this.bar : any
|
||||
>this : any
|
||||
>bar : any
|
||||
|
||||
},
|
||||
bar() {
|
||||
>bar : () => number
|
||||
|
||||
return 14;
|
||||
>14 : number
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,26 +1,54 @@
|
||||
interface Arguments {
|
||||
init?: (this: void) => void;
|
||||
interface IndexedWithThis {
|
||||
// this is a workaround for React
|
||||
init?: (this: this) => void;
|
||||
willDestroy?: (this: any) => void;
|
||||
[propName: string]: number | string | boolean | symbol | undefined | null | {} | ((this: any, ...args:any[]) => any);
|
||||
}
|
||||
declare function extend(arguments: Arguments): void;
|
||||
class Mixin {
|
||||
stuff: number;
|
||||
interface IndexedWithoutThis {
|
||||
// this is what React would like to write (and what they write today)
|
||||
init?: () => void;
|
||||
willDestroy?: () => void;
|
||||
[propName: string]: any;
|
||||
}
|
||||
interface SimpleInterface {
|
||||
foo(n: string);
|
||||
bar(): number;
|
||||
}
|
||||
declare function extend1(args: IndexedWithThis): void;
|
||||
declare function extend2(args: IndexedWithoutThis): void;
|
||||
declare function simple(arg: SimpleInterface): void;
|
||||
|
||||
extend({
|
||||
extend1({
|
||||
init() {
|
||||
this
|
||||
this // this: IndexedWithThis because of contextual typing.
|
||||
// this.mine
|
||||
this.willDestroy
|
||||
},
|
||||
mine: 12,
|
||||
bar() {
|
||||
this.init();
|
||||
},
|
||||
foo() {
|
||||
this.bar;
|
||||
this.url
|
||||
this.handler()
|
||||
this.baz
|
||||
this.url; // this: any because 'foo' matches the string indexer
|
||||
this.willDestroy;
|
||||
}
|
||||
});
|
||||
extend2({
|
||||
init() {
|
||||
this // this: any because the contextual signature of init doesn't specify this' type
|
||||
this.mine
|
||||
this.willDestroy
|
||||
},
|
||||
mine: 13,
|
||||
foo() {
|
||||
this // this: any because of the string indexer
|
||||
this.mine
|
||||
this.willDestroy
|
||||
}
|
||||
});
|
||||
|
||||
simple({
|
||||
foo(n) {
|
||||
return n.length + this.bar();
|
||||
},
|
||||
bar() {
|
||||
return 14;
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user