mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-04-17 01:49:41 -05:00
Allow this when it appears in this is T positions (#59310)
This commit is contained in:
@@ -40980,10 +40980,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
checkSourceElement(node.type);
|
||||
|
||||
const { parameterName } = node;
|
||||
if (typePredicate.kind === TypePredicateKind.This || typePredicate.kind === TypePredicateKind.AssertsThis) {
|
||||
getTypeFromThisTypeNode(parameterName as ThisTypeNode);
|
||||
}
|
||||
else {
|
||||
if (typePredicate.kind !== TypePredicateKind.This && typePredicate.kind !== TypePredicateKind.AssertsThis) {
|
||||
if (typePredicate.parameterIndex >= 0) {
|
||||
if (signatureHasRestParameter(signature) && typePredicate.parameterIndex === signature.parameters.length - 1) {
|
||||
error(parameterName, Diagnostics.A_type_predicate_cannot_reference_a_rest_parameter);
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
declarationEmitThisPredicates02.ts(8,10): error TS2526: A 'this' type is available only in a non-static member of a class or interface.
|
||||
|
||||
|
||||
==== declarationEmitThisPredicates02.ts (1 errors) ====
|
||||
export interface Foo {
|
||||
a: string;
|
||||
b: number;
|
||||
c: boolean;
|
||||
}
|
||||
|
||||
export const obj = {
|
||||
m(): this is Foo {
|
||||
~~~~
|
||||
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
|
||||
let dis = this as {} as Foo;
|
||||
return dis.a != null && dis.b != null && dis.c != null;
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,6 @@ export const obj = {
|
||||
>this as {} : {}
|
||||
> : ^^
|
||||
>this : any
|
||||
> : ^^^
|
||||
|
||||
return dis.a != null && dis.b != null && dis.c != null;
|
||||
>dis.a != null && dis.b != null && dis.c != null : boolean
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
declarationEmitThisPredicatesWithPrivateName02.ts(8,10): error TS2526: A 'this' type is available only in a non-static member of a class or interface.
|
||||
|
||||
|
||||
==== declarationEmitThisPredicatesWithPrivateName02.ts (1 errors) ====
|
||||
interface Foo {
|
||||
a: string;
|
||||
b: number;
|
||||
c: boolean;
|
||||
}
|
||||
|
||||
export const obj = {
|
||||
m(): this is Foo {
|
||||
~~~~
|
||||
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
|
||||
let dis = this as {} as Foo;
|
||||
return dis.a != null && dis.b != null && dis.c != null;
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,6 @@ export const obj = {
|
||||
>this as {} : {}
|
||||
> : ^^
|
||||
>this : any
|
||||
> : ^^^
|
||||
|
||||
return dis.a != null && dis.b != null && dis.c != null;
|
||||
>dis.a != null && dis.b != null && dis.c != null : boolean
|
||||
|
||||
@@ -107,113 +107,3 @@ export declare const thing: {
|
||||
readonly [Symbol.unscopables]?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//// [DtsFileErrors]
|
||||
|
||||
|
||||
mappedTypeWithAsClauseAndLateBoundProperty2.d.ts(27,118): error TS2526: A 'this' type is available only in a non-static member of a class or interface.
|
||||
|
||||
|
||||
==== mappedTypeWithAsClauseAndLateBoundProperty2.d.ts (1 errors) ====
|
||||
export declare const thing: {
|
||||
[x: number]: number;
|
||||
toString: () => string;
|
||||
toLocaleString: {
|
||||
(): string;
|
||||
(locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string;
|
||||
};
|
||||
pop: () => number;
|
||||
push: (...items: number[]) => number;
|
||||
concat: {
|
||||
(...items: ConcatArray<number>[]): number[];
|
||||
(...items: (number | ConcatArray<number>)[]): number[];
|
||||
};
|
||||
join: (separator?: string) => string;
|
||||
reverse: () => number[];
|
||||
shift: () => number;
|
||||
slice: (start?: number, end?: number) => number[];
|
||||
sort: (compareFn?: (a: number, b: number) => number) => number[];
|
||||
splice: {
|
||||
(start: number, deleteCount?: number): number[];
|
||||
(start: number, deleteCount: number, ...items: number[]): number[];
|
||||
};
|
||||
unshift: (...items: number[]) => number;
|
||||
indexOf: (searchElement: number, fromIndex?: number) => number;
|
||||
lastIndexOf: (searchElement: number, fromIndex?: number) => number;
|
||||
every: {
|
||||
<S extends number>(predicate: (value: number, index: number, array: number[]) => value is S, thisArg?: any): this is S[];
|
||||
~~~~
|
||||
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
|
||||
(predicate: (value: number, index: number, array: number[]) => unknown, thisArg?: any): boolean;
|
||||
};
|
||||
some: (predicate: (value: number, index: number, array: number[]) => unknown, thisArg?: any) => boolean;
|
||||
forEach: (callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any) => void;
|
||||
map: <U>(callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any) => U[];
|
||||
filter: {
|
||||
<S extends number>(predicate: (value: number, index: number, array: number[]) => value is S, thisArg?: any): S[];
|
||||
(predicate: (value: number, index: number, array: number[]) => unknown, thisArg?: any): number[];
|
||||
};
|
||||
reduce: {
|
||||
(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number): number;
|
||||
(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number, initialValue: number): number;
|
||||
<U>(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: number[]) => U, initialValue: U): U;
|
||||
};
|
||||
reduceRight: {
|
||||
(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number): number;
|
||||
(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number, initialValue: number): number;
|
||||
<U>(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: number[]) => U, initialValue: U): U;
|
||||
};
|
||||
find: {
|
||||
<S extends number>(predicate: (value: number, index: number, obj: number[]) => value is S, thisArg?: any): S;
|
||||
(predicate: (value: number, index: number, obj: number[]) => unknown, thisArg?: any): number;
|
||||
};
|
||||
findIndex: (predicate: (value: number, index: number, obj: number[]) => unknown, thisArg?: any) => number;
|
||||
fill: (value: number, start?: number, end?: number) => number[];
|
||||
copyWithin: (target: number, start: number, end?: number) => number[];
|
||||
entries: () => BuiltinIterator<[number, number], any, any>;
|
||||
keys: () => BuiltinIterator<number, BuiltinIteratorReturn>;
|
||||
values: () => BuiltinIterator<number, any, any>;
|
||||
includes: (searchElement: number, fromIndex?: number) => boolean;
|
||||
flatMap: <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U | readonly U[], thisArg?: This) => U[];
|
||||
flat: <A, D extends number = 1>(this: A, depth?: D) => FlatArray<A, D>[];
|
||||
[Symbol.iterator]: () => BuiltinIterator<number, any, any>;
|
||||
readonly [Symbol.unscopables]: {
|
||||
[x: number]: boolean;
|
||||
length?: boolean;
|
||||
toString?: boolean;
|
||||
toLocaleString?: boolean;
|
||||
pop?: boolean;
|
||||
push?: boolean;
|
||||
concat?: boolean;
|
||||
join?: boolean;
|
||||
reverse?: boolean;
|
||||
shift?: boolean;
|
||||
slice?: boolean;
|
||||
sort?: boolean;
|
||||
splice?: boolean;
|
||||
unshift?: boolean;
|
||||
indexOf?: boolean;
|
||||
lastIndexOf?: boolean;
|
||||
every?: boolean;
|
||||
some?: boolean;
|
||||
forEach?: boolean;
|
||||
map?: boolean;
|
||||
filter?: boolean;
|
||||
reduce?: boolean;
|
||||
reduceRight?: boolean;
|
||||
find?: boolean;
|
||||
findIndex?: boolean;
|
||||
fill?: boolean;
|
||||
copyWithin?: boolean;
|
||||
entries?: boolean;
|
||||
keys?: boolean;
|
||||
values?: boolean;
|
||||
includes?: boolean;
|
||||
flatMap?: boolean;
|
||||
flat?: boolean;
|
||||
[Symbol.iterator]?: boolean;
|
||||
readonly [Symbol.unscopables]?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
thisPredicateInObjectLiteral.ts(10,28): error TS2526: A 'this' type is available only in a non-static member of a class or interface.
|
||||
|
||||
|
||||
==== thisPredicateInObjectLiteral.ts (1 errors) ====
|
||||
// Should be OK
|
||||
const foo2 = {
|
||||
isNumber(): this is { b: string } {
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
// Still an error
|
||||
const foo3 = {
|
||||
isNumber(x: any): x is this {
|
||||
~~~~
|
||||
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
32
tests/baselines/reference/thisPredicateInObjectLiteral.js
Normal file
32
tests/baselines/reference/thisPredicateInObjectLiteral.js
Normal file
@@ -0,0 +1,32 @@
|
||||
//// [tests/cases/compiler/thisPredicateInObjectLiteral.ts] ////
|
||||
|
||||
//// [thisPredicateInObjectLiteral.ts]
|
||||
// Should be OK
|
||||
const foo2 = {
|
||||
isNumber(): this is { b: string } {
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
// Still an error
|
||||
const foo3 = {
|
||||
isNumber(x: any): x is this {
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
//// [thisPredicateInObjectLiteral.js]
|
||||
"use strict";
|
||||
// Should be OK
|
||||
var foo2 = {
|
||||
isNumber: function () {
|
||||
return true;
|
||||
},
|
||||
};
|
||||
// Still an error
|
||||
var foo3 = {
|
||||
isNumber: function (x) {
|
||||
return true;
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
//// [tests/cases/compiler/thisPredicateInObjectLiteral.ts] ////
|
||||
|
||||
=== thisPredicateInObjectLiteral.ts ===
|
||||
// Should be OK
|
||||
const foo2 = {
|
||||
>foo2 : Symbol(foo2, Decl(thisPredicateInObjectLiteral.ts, 1, 5))
|
||||
|
||||
isNumber(): this is { b: string } {
|
||||
>isNumber : Symbol(isNumber, Decl(thisPredicateInObjectLiteral.ts, 1, 14))
|
||||
>b : Symbol(b, Decl(thisPredicateInObjectLiteral.ts, 2, 25))
|
||||
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
// Still an error
|
||||
const foo3 = {
|
||||
>foo3 : Symbol(foo3, Decl(thisPredicateInObjectLiteral.ts, 8, 5))
|
||||
|
||||
isNumber(x: any): x is this {
|
||||
>isNumber : Symbol(isNumber, Decl(thisPredicateInObjectLiteral.ts, 8, 14))
|
||||
>x : Symbol(x, Decl(thisPredicateInObjectLiteral.ts, 9, 13))
|
||||
>x : Symbol(x, Decl(thisPredicateInObjectLiteral.ts, 9, 13))
|
||||
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
43
tests/baselines/reference/thisPredicateInObjectLiteral.types
Normal file
43
tests/baselines/reference/thisPredicateInObjectLiteral.types
Normal file
@@ -0,0 +1,43 @@
|
||||
//// [tests/cases/compiler/thisPredicateInObjectLiteral.ts] ////
|
||||
|
||||
=== thisPredicateInObjectLiteral.ts ===
|
||||
// Should be OK
|
||||
const foo2 = {
|
||||
>foo2 : { isNumber(): this is { b: string; }; }
|
||||
> : ^^^^^^^^^^^^^^ ^^^
|
||||
>{ isNumber(): this is { b: string } { return true; },} : { isNumber(): this is { b: string; }; }
|
||||
> : ^^^^^^^^^^^^^^ ^^^
|
||||
|
||||
isNumber(): this is { b: string } {
|
||||
>isNumber : () => this is { b: string; }
|
||||
> : ^^^^^^
|
||||
>b : string
|
||||
> : ^^^^^^
|
||||
|
||||
return true;
|
||||
>true : true
|
||||
> : ^^^^
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
// Still an error
|
||||
const foo3 = {
|
||||
>foo3 : { isNumber(x: any): x is this; }
|
||||
> : ^^^^^^^^^^^ ^^ ^^^ ^^^
|
||||
>{ isNumber(x: any): x is this { return true; },} : { isNumber(x: any): x is this; }
|
||||
> : ^^^^^^^^^^^ ^^ ^^^ ^^^
|
||||
|
||||
isNumber(x: any): x is this {
|
||||
>isNumber : (x: any) => x is this
|
||||
> : ^ ^^ ^^^^^
|
||||
>x : any
|
||||
> : ^^^
|
||||
|
||||
return true;
|
||||
>true : true
|
||||
> : ^^^^
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
@@ -10,12 +10,11 @@ typeGuardFunctionOfFormThisErrors.ts(26,1): error TS2322: Type '() => this is Le
|
||||
typeGuardFunctionOfFormThisErrors.ts(27,1): error TS2322: Type '() => this is FollowerGuard' is not assignable to type '() => this is LeadGuard'.
|
||||
Type predicate 'this is FollowerGuard' is not assignable to 'this is LeadGuard'.
|
||||
Property 'lead' is missing in type 'FollowerGuard' but required in type 'LeadGuard'.
|
||||
typeGuardFunctionOfFormThisErrors.ts(29,32): error TS2526: A 'this' type is available only in a non-static member of a class or interface.
|
||||
typeGuardFunctionOfFormThisErrors.ts(55,7): error TS2339: Property 'follow' does not exist on type 'RoyalGuard'.
|
||||
typeGuardFunctionOfFormThisErrors.ts(58,7): error TS2339: Property 'lead' does not exist on type 'RoyalGuard'.
|
||||
|
||||
|
||||
==== typeGuardFunctionOfFormThisErrors.ts (7 errors) ====
|
||||
==== typeGuardFunctionOfFormThisErrors.ts (6 errors) ====
|
||||
class RoyalGuard {
|
||||
isLeader(): this is LeadGuard {
|
||||
return this instanceof LeadGuard;
|
||||
@@ -65,8 +64,6 @@ typeGuardFunctionOfFormThisErrors.ts(58,7): error TS2339: Property 'lead' does n
|
||||
!!! related TS2728 typeGuardFunctionOfFormThisErrors.ts:11:5: 'lead' is declared here.
|
||||
|
||||
function invalidGuard(c: any): this is number {
|
||||
~~~~
|
||||
!!! error TS2526: A 'this' type is available only in a non-static member of a class or interface.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
15
tests/cases/compiler/thisPredicateInObjectLiteral.ts
Normal file
15
tests/cases/compiler/thisPredicateInObjectLiteral.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
// @strict: true
|
||||
|
||||
// Should be OK
|
||||
const foo2 = {
|
||||
isNumber(): this is { b: string } {
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
// Still an error
|
||||
const foo3 = {
|
||||
isNumber(x: any): x is this {
|
||||
return true;
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user