diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 04facba3196e7..87eb3126eed50 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27181,7 +27181,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return target.kind === SyntaxKind.SuperKeyword; case SyntaxKind.NonNullExpression: case SyntaxKind.ParenthesizedExpression: - return isMatchingReference((source as NonNullExpression | ParenthesizedExpression).expression, target); + case SyntaxKind.SatisfiesExpression: + return isMatchingReference((source as NonNullExpression | ParenthesizedExpression | SatisfiesExpression).expression, target); case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: const sourcePropertyName = getAccessedPropertyName(source as AccessExpression); @@ -29532,7 +29533,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return narrowTypeByCallExpression(type, expr as CallExpression, assumeTrue); case SyntaxKind.ParenthesizedExpression: case SyntaxKind.NonNullExpression: - return narrowType(type, (expr as ParenthesizedExpression | NonNullExpression).expression, assumeTrue); + case SyntaxKind.SatisfiesExpression: + return narrowType(type, (expr as ParenthesizedExpression | NonNullExpression | SatisfiesExpression).expression, assumeTrue); case SyntaxKind.BinaryExpression: return narrowTypeByBinaryExpression(type, expr as BinaryExpression, assumeTrue); case SyntaxKind.PrefixUnaryExpression: diff --git a/tests/baselines/reference/inferTypePredicates.errors.txt b/tests/baselines/reference/inferTypePredicates.errors.txt index 6a955c7cb0671..9701d6aeed82f 100644 --- a/tests/baselines/reference/inferTypePredicates.errors.txt +++ b/tests/baselines/reference/inferTypePredicates.errors.txt @@ -333,4 +333,14 @@ inferTypePredicates.ts(205,7): error TS2741: Property 'z' is missing in type 'C1 if (foobarPred(foobar)) { foobar.foo; } + + // https://github.com/microsoft/TypeScript/issues/60778 + const arrTest: Array = [1, 2, null, 3].filter( + (x) => (x != null) satisfies boolean, + ); + + function isEmptyString(x: unknown) { + const rv = x === ""; + return rv satisfies boolean; + } \ No newline at end of file diff --git a/tests/baselines/reference/inferTypePredicates.js b/tests/baselines/reference/inferTypePredicates.js index 315652eec06d0..725c3eb6b0b34 100644 --- a/tests/baselines/reference/inferTypePredicates.js +++ b/tests/baselines/reference/inferTypePredicates.js @@ -279,6 +279,16 @@ const foobarPred = (fb: typeof foobar) => fb.type === "foo"; if (foobarPred(foobar)) { foobar.foo; } + +// https://github.com/microsoft/TypeScript/issues/60778 +const arrTest: Array = [1, 2, null, 3].filter( + (x) => (x != null) satisfies boolean, +); + +function isEmptyString(x: unknown) { + const rv = x === ""; + return rv satisfies boolean; +} //// [inferTypePredicates.js] @@ -538,6 +548,12 @@ var foobarPred = function (fb) { return fb.type === "foo"; }; if (foobarPred(foobar)) { foobar.foo; } +// https://github.com/microsoft/TypeScript/issues/60778 +var arrTest = [1, 2, null, 3].filter(function (x) { return (x != null); }); +function isEmptyString(x) { + var rv = x === ""; + return rv; +} //// [inferTypePredicates.d.ts] @@ -630,3 +646,5 @@ declare const foobarPred: (fb: typeof foobar) => fb is { type: "foo"; foo: number; }; +declare const arrTest: Array; +declare function isEmptyString(x: unknown): x is ""; diff --git a/tests/baselines/reference/inferTypePredicates.symbols b/tests/baselines/reference/inferTypePredicates.symbols index 8fd879787c205..aec451e86fd4b 100644 --- a/tests/baselines/reference/inferTypePredicates.symbols +++ b/tests/baselines/reference/inferTypePredicates.symbols @@ -777,3 +777,28 @@ if (foobarPred(foobar)) { >foo : Symbol(foo, Decl(inferTypePredicates.ts, 271, 18)) } +// https://github.com/microsoft/TypeScript/issues/60778 +const arrTest: Array = [1, 2, null, 3].filter( +>arrTest : Symbol(arrTest, Decl(inferTypePredicates.ts, 280, 5)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>[1, 2, null, 3].filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + (x) => (x != null) satisfies boolean, +>x : Symbol(x, Decl(inferTypePredicates.ts, 281, 3)) +>x : Symbol(x, Decl(inferTypePredicates.ts, 281, 3)) + +); + +function isEmptyString(x: unknown) { +>isEmptyString : Symbol(isEmptyString, Decl(inferTypePredicates.ts, 282, 2)) +>x : Symbol(x, Decl(inferTypePredicates.ts, 284, 23)) + + const rv = x === ""; +>rv : Symbol(rv, Decl(inferTypePredicates.ts, 285, 7)) +>x : Symbol(x, Decl(inferTypePredicates.ts, 284, 23)) + + return rv satisfies boolean; +>rv : Symbol(rv, Decl(inferTypePredicates.ts, 285, 7)) +} + diff --git a/tests/baselines/reference/inferTypePredicates.types b/tests/baselines/reference/inferTypePredicates.types index e604e593a0e2f..326617e83ba05 100644 --- a/tests/baselines/reference/inferTypePredicates.types +++ b/tests/baselines/reference/inferTypePredicates.types @@ -1649,3 +1649,61 @@ if (foobarPred(foobar)) { > : ^^^^^^ } +// https://github.com/microsoft/TypeScript/issues/60778 +const arrTest: Array = [1, 2, null, 3].filter( +>arrTest : number[] +> : ^^^^^^^^ +>[1, 2, null, 3].filter( (x) => (x != null) satisfies boolean,) : number[] +> : ^^^^^^^^ +>[1, 2, null, 3].filter : { (predicate: (value: number | null, index: number, array: (number | null)[]) => value is S, thisArg?: any): S[]; (predicate: (value: number | null, index: number, array: (number | null)[]) => unknown, thisArg?: any): (number | null)[]; } +> : ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ +>[1, 2, null, 3] : (number | null)[] +> : ^^^^^^^^^^^^^^^^^ +>1 : 1 +> : ^ +>2 : 2 +> : ^ +>3 : 3 +> : ^ +>filter : { (predicate: (value: number | null, index: number, array: (number | null)[]) => value is S, thisArg?: any): S[]; (predicate: (value: number | null, index: number, array: (number | null)[]) => unknown, thisArg?: any): (number | null)[]; } +> : ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ + + (x) => (x != null) satisfies boolean, +>(x) => (x != null) satisfies boolean : (x: number | null) => x is number +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>x : number | null +> : ^^^^^^^^^^^^^ +>(x != null) satisfies boolean : boolean +> : ^^^^^^^ +>(x != null) : boolean +> : ^^^^^^^ +>x != null : boolean +> : ^^^^^^^ +>x : number | null +> : ^^^^^^^^^^^^^ + +); + +function isEmptyString(x: unknown) { +>isEmptyString : (x: unknown) => x is "" +> : ^ ^^ ^^^^^^^^^^^^ +>x : unknown +> : ^^^^^^^ + + const rv = x === ""; +>rv : boolean +> : ^^^^^^^ +>x === "" : boolean +> : ^^^^^^^ +>x : unknown +> : ^^^^^^^ +>"" : "" +> : ^^ + + return rv satisfies boolean; +>rv satisfies boolean : boolean +> : ^^^^^^^ +>rv : boolean +> : ^^^^^^^ +} + diff --git a/tests/cases/compiler/inferTypePredicates.ts b/tests/cases/compiler/inferTypePredicates.ts index 9b996ee8c8414..bb8e6132f4279 100644 --- a/tests/cases/compiler/inferTypePredicates.ts +++ b/tests/cases/compiler/inferTypePredicates.ts @@ -279,3 +279,13 @@ const foobarPred = (fb: typeof foobar) => fb.type === "foo"; if (foobarPred(foobar)) { foobar.foo; } + +// https://github.com/microsoft/TypeScript/issues/60778 +const arrTest: Array = [1, 2, null, 3].filter( + (x) => (x != null) satisfies boolean, +); + +function isEmptyString(x: unknown) { + const rv = x === ""; + return rv satisfies boolean; +}