Skip to content

Commit

Permalink
Allow this when it appears in this is T positions (#59310)
Browse files Browse the repository at this point in the history
  • Loading branch information
RyanCavanaugh authored Aug 2, 2024
1 parent 8daac14 commit ffb9585
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 156 deletions.
5 changes: 1 addition & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
};

20 changes: 20 additions & 0 deletions tests/baselines/reference/thisPredicateInObjectLiteral.errors.txt
Original file line number Diff line number Diff line change
@@ -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 changes: 32 additions & 0 deletions tests/baselines/reference/thisPredicateInObjectLiteral.js
Original file line number Diff line number Diff line change
@@ -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;
},
};
28 changes: 28 additions & 0 deletions tests/baselines/reference/thisPredicateInObjectLiteral.symbols
Original file line number Diff line number Diff line change
@@ -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 changes: 43 additions & 0 deletions tests/baselines/reference/thisPredicateInObjectLiteral.types
Original file line number Diff line number Diff line change
@@ -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
> : ^^^^

},
};

Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
15 changes: 15 additions & 0 deletions tests/cases/compiler/thisPredicateInObjectLiteral.ts
Original file line number Diff line number Diff line change
@@ -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;
},
};

0 comments on commit ffb9585

Please sign in to comment.