mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-13 14:29:00 -06:00
Use contextual type to determine 'this' when determining member visibility (#56105)
This commit is contained in:
parent
269219f68e
commit
aafdfe5b3f
@ -33667,10 +33667,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function getEnclosingClassFromThisParameter(node: Node): InterfaceType | undefined {
|
||||
// 'this' type for a node comes from, in priority order...
|
||||
// 1. The type of a syntactic 'this' parameter in the enclosing function scope
|
||||
const thisParameter = getThisParameterFromNodeContext(node);
|
||||
let thisType = thisParameter?.type && getTypeFromTypeNode(thisParameter.type);
|
||||
if (thisType && thisType.flags & TypeFlags.TypeParameter) {
|
||||
thisType = getConstraintOfTypeParameter(thisType as TypeParameter);
|
||||
if (thisType) {
|
||||
// 2. The constraint of a type parameter used for an explicit 'this' parameter
|
||||
if (thisType.flags & TypeFlags.TypeParameter) {
|
||||
thisType = getConstraintOfTypeParameter(thisType as TypeParameter);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 3. The 'this' parameter of a contextual type
|
||||
const thisContainer = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false);
|
||||
if (isFunctionLike(thisContainer)) {
|
||||
thisType = getContextualThisParameterType(thisContainer);
|
||||
}
|
||||
}
|
||||
if (thisType && getObjectFlags(thisType) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference)) {
|
||||
return getTargetType(thisType) as InterfaceType;
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
protectedAccessThroughContextualThis.ts(13,20): error TS2341: Property 'privat' is private and only accessible within class 'Foo'.
|
||||
protectedAccessThroughContextualThis.ts(20,20): error TS2341: Property 'privat' is private and only accessible within class 'Foo'.
|
||||
|
||||
|
||||
==== protectedAccessThroughContextualThis.ts (2 errors) ====
|
||||
class Foo {
|
||||
protected protec = 'bar';
|
||||
private privat = '';
|
||||
copy!: string
|
||||
constructor() {
|
||||
bindCopy.call(this)
|
||||
bindCopy2.call(this)
|
||||
}
|
||||
}
|
||||
|
||||
function bindCopy(this: Foo) {
|
||||
this.copy = this.protec; // Should OK
|
||||
console.log(this.privat); // Should error
|
||||
~~~~~~
|
||||
!!! error TS2341: Property 'privat' is private and only accessible within class 'Foo'.
|
||||
}
|
||||
|
||||
type BindingFunction = (this: Foo) => void;
|
||||
|
||||
const bindCopy2: BindingFunction = function () {
|
||||
this.copy = this.protec; // Should OK
|
||||
console.log(this.privat); // Should error
|
||||
~~~~~~
|
||||
!!! error TS2341: Property 'privat' is private and only accessible within class 'Foo'.
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
//// [tests/cases/compiler/protectedAccessThroughContextualThis.ts] ////
|
||||
|
||||
//// [protectedAccessThroughContextualThis.ts]
|
||||
class Foo {
|
||||
protected protec = 'bar';
|
||||
private privat = '';
|
||||
copy!: string
|
||||
constructor() {
|
||||
bindCopy.call(this)
|
||||
bindCopy2.call(this)
|
||||
}
|
||||
}
|
||||
|
||||
function bindCopy(this: Foo) {
|
||||
this.copy = this.protec; // Should OK
|
||||
console.log(this.privat); // Should error
|
||||
}
|
||||
|
||||
type BindingFunction = (this: Foo) => void;
|
||||
|
||||
const bindCopy2: BindingFunction = function () {
|
||||
this.copy = this.protec; // Should OK
|
||||
console.log(this.privat); // Should error
|
||||
}
|
||||
|
||||
//// [protectedAccessThroughContextualThis.js]
|
||||
"use strict";
|
||||
var Foo = /** @class */ (function () {
|
||||
function Foo() {
|
||||
this.protec = 'bar';
|
||||
this.privat = '';
|
||||
bindCopy.call(this);
|
||||
bindCopy2.call(this);
|
||||
}
|
||||
return Foo;
|
||||
}());
|
||||
function bindCopy() {
|
||||
this.copy = this.protec; // Should OK
|
||||
console.log(this.privat); // Should error
|
||||
}
|
||||
var bindCopy2 = function () {
|
||||
this.copy = this.protec; // Should OK
|
||||
console.log(this.privat); // Should error
|
||||
};
|
||||
@ -0,0 +1,77 @@
|
||||
//// [tests/cases/compiler/protectedAccessThroughContextualThis.ts] ////
|
||||
|
||||
=== protectedAccessThroughContextualThis.ts ===
|
||||
class Foo {
|
||||
>Foo : Symbol(Foo, Decl(protectedAccessThroughContextualThis.ts, 0, 0))
|
||||
|
||||
protected protec = 'bar';
|
||||
>protec : Symbol(Foo.protec, Decl(protectedAccessThroughContextualThis.ts, 0, 11))
|
||||
|
||||
private privat = '';
|
||||
>privat : Symbol(Foo.privat, Decl(protectedAccessThroughContextualThis.ts, 1, 27))
|
||||
|
||||
copy!: string
|
||||
>copy : Symbol(Foo.copy, Decl(protectedAccessThroughContextualThis.ts, 2, 22))
|
||||
|
||||
constructor() {
|
||||
bindCopy.call(this)
|
||||
>bindCopy.call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --))
|
||||
>bindCopy : Symbol(bindCopy, Decl(protectedAccessThroughContextualThis.ts, 8, 1))
|
||||
>call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --))
|
||||
>this : Symbol(Foo, Decl(protectedAccessThroughContextualThis.ts, 0, 0))
|
||||
|
||||
bindCopy2.call(this)
|
||||
>bindCopy2.call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --))
|
||||
>bindCopy2 : Symbol(bindCopy2, Decl(protectedAccessThroughContextualThis.ts, 17, 5))
|
||||
>call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --))
|
||||
>this : Symbol(Foo, Decl(protectedAccessThroughContextualThis.ts, 0, 0))
|
||||
}
|
||||
}
|
||||
|
||||
function bindCopy(this: Foo) {
|
||||
>bindCopy : Symbol(bindCopy, Decl(protectedAccessThroughContextualThis.ts, 8, 1))
|
||||
>this : Symbol(this, Decl(protectedAccessThroughContextualThis.ts, 10, 18))
|
||||
>Foo : Symbol(Foo, Decl(protectedAccessThroughContextualThis.ts, 0, 0))
|
||||
|
||||
this.copy = this.protec; // Should OK
|
||||
>this.copy : Symbol(Foo.copy, Decl(protectedAccessThroughContextualThis.ts, 2, 22))
|
||||
>this : Symbol(this, Decl(protectedAccessThroughContextualThis.ts, 10, 18))
|
||||
>copy : Symbol(Foo.copy, Decl(protectedAccessThroughContextualThis.ts, 2, 22))
|
||||
>this.protec : Symbol(Foo.protec, Decl(protectedAccessThroughContextualThis.ts, 0, 11))
|
||||
>this : Symbol(this, Decl(protectedAccessThroughContextualThis.ts, 10, 18))
|
||||
>protec : Symbol(Foo.protec, Decl(protectedAccessThroughContextualThis.ts, 0, 11))
|
||||
|
||||
console.log(this.privat); // Should error
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>this.privat : Symbol(Foo.privat, Decl(protectedAccessThroughContextualThis.ts, 1, 27))
|
||||
>this : Symbol(this, Decl(protectedAccessThroughContextualThis.ts, 10, 18))
|
||||
>privat : Symbol(Foo.privat, Decl(protectedAccessThroughContextualThis.ts, 1, 27))
|
||||
}
|
||||
|
||||
type BindingFunction = (this: Foo) => void;
|
||||
>BindingFunction : Symbol(BindingFunction, Decl(protectedAccessThroughContextualThis.ts, 13, 1))
|
||||
>this : Symbol(this, Decl(protectedAccessThroughContextualThis.ts, 15, 24))
|
||||
>Foo : Symbol(Foo, Decl(protectedAccessThroughContextualThis.ts, 0, 0))
|
||||
|
||||
const bindCopy2: BindingFunction = function () {
|
||||
>bindCopy2 : Symbol(bindCopy2, Decl(protectedAccessThroughContextualThis.ts, 17, 5))
|
||||
>BindingFunction : Symbol(BindingFunction, Decl(protectedAccessThroughContextualThis.ts, 13, 1))
|
||||
|
||||
this.copy = this.protec; // Should OK
|
||||
>this.copy : Symbol(Foo.copy, Decl(protectedAccessThroughContextualThis.ts, 2, 22))
|
||||
>this : Symbol(this, Decl(protectedAccessThroughContextualThis.ts, 15, 24))
|
||||
>copy : Symbol(Foo.copy, Decl(protectedAccessThroughContextualThis.ts, 2, 22))
|
||||
>this.protec : Symbol(Foo.protec, Decl(protectedAccessThroughContextualThis.ts, 0, 11))
|
||||
>this : Symbol(this, Decl(protectedAccessThroughContextualThis.ts, 15, 24))
|
||||
>protec : Symbol(Foo.protec, Decl(protectedAccessThroughContextualThis.ts, 0, 11))
|
||||
|
||||
console.log(this.privat); // Should error
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>this.privat : Symbol(Foo.privat, Decl(protectedAccessThroughContextualThis.ts, 1, 27))
|
||||
>this : Symbol(this, Decl(protectedAccessThroughContextualThis.ts, 15, 24))
|
||||
>privat : Symbol(Foo.privat, Decl(protectedAccessThroughContextualThis.ts, 1, 27))
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
//// [tests/cases/compiler/protectedAccessThroughContextualThis.ts] ////
|
||||
|
||||
=== protectedAccessThroughContextualThis.ts ===
|
||||
class Foo {
|
||||
>Foo : Foo
|
||||
> : ^^^
|
||||
|
||||
protected protec = 'bar';
|
||||
>protec : string
|
||||
> : ^^^^^^
|
||||
>'bar' : "bar"
|
||||
> : ^^^^^
|
||||
|
||||
private privat = '';
|
||||
>privat : string
|
||||
> : ^^^^^^
|
||||
>'' : ""
|
||||
> : ^^
|
||||
|
||||
copy!: string
|
||||
>copy : string
|
||||
> : ^^^^^^
|
||||
|
||||
constructor() {
|
||||
bindCopy.call(this)
|
||||
>bindCopy.call(this) : void
|
||||
> : ^^^^
|
||||
>bindCopy.call : <T, A extends any[], R>(this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R
|
||||
> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^
|
||||
>bindCopy : (this: Foo) => void
|
||||
> : ^ ^^ ^^^^^^^^^
|
||||
>call : <T, A extends any[], R>(this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R
|
||||
> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^
|
||||
>this : this
|
||||
> : ^^^^
|
||||
|
||||
bindCopy2.call(this)
|
||||
>bindCopy2.call(this) : void
|
||||
> : ^^^^
|
||||
>bindCopy2.call : <T, A extends any[], R>(this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R
|
||||
> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^
|
||||
>bindCopy2 : BindingFunction
|
||||
> : ^^^^^^^^^^^^^^^
|
||||
>call : <T, A extends any[], R>(this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R
|
||||
> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^
|
||||
>this : this
|
||||
> : ^^^^
|
||||
}
|
||||
}
|
||||
|
||||
function bindCopy(this: Foo) {
|
||||
>bindCopy : (this: Foo) => void
|
||||
> : ^ ^^ ^^^^^^^^^
|
||||
>this : Foo
|
||||
> : ^^^
|
||||
|
||||
this.copy = this.protec; // Should OK
|
||||
>this.copy = this.protec : string
|
||||
> : ^^^^^^
|
||||
>this.copy : string
|
||||
> : ^^^^^^
|
||||
>this : Foo
|
||||
> : ^^^
|
||||
>copy : string
|
||||
> : ^^^^^^
|
||||
>this.protec : string
|
||||
> : ^^^^^^
|
||||
>this : Foo
|
||||
> : ^^^
|
||||
>protec : string
|
||||
> : ^^^^^^
|
||||
|
||||
console.log(this.privat); // Should error
|
||||
>console.log(this.privat) : void
|
||||
> : ^^^^
|
||||
>console.log : (...data: any[]) => void
|
||||
> : ^^^^ ^^ ^^^^^
|
||||
>console : Console
|
||||
> : ^^^^^^^
|
||||
>log : (...data: any[]) => void
|
||||
> : ^^^^ ^^ ^^^^^
|
||||
>this.privat : string
|
||||
> : ^^^^^^
|
||||
>this : Foo
|
||||
> : ^^^
|
||||
>privat : string
|
||||
> : ^^^^^^
|
||||
}
|
||||
|
||||
type BindingFunction = (this: Foo) => void;
|
||||
>BindingFunction : BindingFunction
|
||||
> : ^^^^^^^^^^^^^^^
|
||||
>this : Foo
|
||||
> : ^^^
|
||||
|
||||
const bindCopy2: BindingFunction = function () {
|
||||
>bindCopy2 : BindingFunction
|
||||
> : ^^^^^^^^^^^^^^^
|
||||
>function () { this.copy = this.protec; // Should OK console.log(this.privat); // Should error} : (this: Foo) => void
|
||||
> : ^ ^^ ^^^^^^^^^
|
||||
|
||||
this.copy = this.protec; // Should OK
|
||||
>this.copy = this.protec : string
|
||||
> : ^^^^^^
|
||||
>this.copy : string
|
||||
> : ^^^^^^
|
||||
>this : Foo
|
||||
> : ^^^
|
||||
>copy : string
|
||||
> : ^^^^^^
|
||||
>this.protec : string
|
||||
> : ^^^^^^
|
||||
>this : Foo
|
||||
> : ^^^
|
||||
>protec : string
|
||||
> : ^^^^^^
|
||||
|
||||
console.log(this.privat); // Should error
|
||||
>console.log(this.privat) : void
|
||||
> : ^^^^
|
||||
>console.log : (...data: any[]) => void
|
||||
> : ^^^^ ^^ ^^^^^
|
||||
>console : Console
|
||||
> : ^^^^^^^
|
||||
>log : (...data: any[]) => void
|
||||
> : ^^^^ ^^ ^^^^^
|
||||
>this.privat : string
|
||||
> : ^^^^^^
|
||||
>this : Foo
|
||||
> : ^^^
|
||||
>privat : string
|
||||
> : ^^^^^^
|
||||
}
|
||||
23
tests/cases/compiler/protectedAccessThroughContextualThis.ts
Normal file
23
tests/cases/compiler/protectedAccessThroughContextualThis.ts
Normal file
@ -0,0 +1,23 @@
|
||||
// @strict: true
|
||||
|
||||
class Foo {
|
||||
protected protec = 'bar';
|
||||
private privat = '';
|
||||
copy!: string
|
||||
constructor() {
|
||||
bindCopy.call(this)
|
||||
bindCopy2.call(this)
|
||||
}
|
||||
}
|
||||
|
||||
function bindCopy(this: Foo) {
|
||||
this.copy = this.protec; // Should OK
|
||||
console.log(this.privat); // Should error
|
||||
}
|
||||
|
||||
type BindingFunction = (this: Foo) => void;
|
||||
|
||||
const bindCopy2: BindingFunction = function () {
|
||||
this.copy = this.protec; // Should OK
|
||||
console.log(this.privat); // Should error
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user