diff --git a/tests/baselines/reference/inferTypePredicates.errors.txt b/tests/baselines/reference/inferTypePredicates.errors.txt index ef4f5da02da..b8ef2508d3b 100644 --- a/tests/baselines/reference/inferTypePredicates.errors.txt +++ b/tests/baselines/reference/inferTypePredicates.errors.txt @@ -284,4 +284,19 @@ inferTypePredicates.ts(205,7): error TS2741: Property 'z' is missing in type 'C1 if (isNumOrStr(unk)) { let t: number | string = unk; // should ok } + + // A function can be a type predicate even if it throws. + function assertAndPredicate(x: string | number | Date) { + if (x instanceof Date) { + throw new Error(); + } + return typeof x === 'string'; + } + + declare let snd: string | number | Date; + if (assertAndPredicate(snd)) { + let t: string = snd; // should ok + } else { + snd; // type is number | Date + } \ No newline at end of file diff --git a/tests/baselines/reference/inferTypePredicates.js b/tests/baselines/reference/inferTypePredicates.js index c0a694a6f90..94b5ed4d8ad 100644 --- a/tests/baselines/reference/inferTypePredicates.js +++ b/tests/baselines/reference/inferTypePredicates.js @@ -241,6 +241,21 @@ declare let unk: unknown; if (isNumOrStr(unk)) { let t: number | string = unk; // should ok } + +// A function can be a type predicate even if it throws. +function assertAndPredicate(x: string | number | Date) { + if (x instanceof Date) { + throw new Error(); + } + return typeof x === 'string'; +} + +declare let snd: string | number | Date; +if (assertAndPredicate(snd)) { + let t: string = snd; // should ok +} else { + snd; // type is number | Date +} //// [inferTypePredicates.js] @@ -459,3 +474,16 @@ function isNumOrStr(x) { if (isNumOrStr(unk)) { var t = unk; // should ok } +// A function can be a type predicate even if it throws. +function assertAndPredicate(x) { + if (x instanceof Date) { + throw new Error(); + } + return typeof x === 'string'; +} +if (assertAndPredicate(snd)) { + var t = snd; // should ok +} +else { + snd; // type is number | Date +} diff --git a/tests/baselines/reference/inferTypePredicates.symbols b/tests/baselines/reference/inferTypePredicates.symbols index b5310e31b7b..adb871430b4 100644 --- a/tests/baselines/reference/inferTypePredicates.symbols +++ b/tests/baselines/reference/inferTypePredicates.symbols @@ -680,3 +680,37 @@ if (isNumOrStr(unk)) { >unk : Symbol(unk, Decl(inferTypePredicates.ts, 236, 11)) } +// A function can be a type predicate even if it throws. +function assertAndPredicate(x: string | number | Date) { +>assertAndPredicate : Symbol(assertAndPredicate, Decl(inferTypePredicates.ts, 239, 1)) +>x : Symbol(x, Decl(inferTypePredicates.ts, 242, 28)) +>Date : Symbol(Date, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.scripthost.d.ts, --, --)) + + if (x instanceof Date) { +>x : Symbol(x, Decl(inferTypePredicates.ts, 242, 28)) +>Date : Symbol(Date, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.scripthost.d.ts, --, --)) + + throw new Error(); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + } + return typeof x === 'string'; +>x : Symbol(x, Decl(inferTypePredicates.ts, 242, 28)) +} + +declare let snd: string | number | Date; +>snd : Symbol(snd, Decl(inferTypePredicates.ts, 249, 11)) +>Date : Symbol(Date, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.scripthost.d.ts, --, --)) + +if (assertAndPredicate(snd)) { +>assertAndPredicate : Symbol(assertAndPredicate, Decl(inferTypePredicates.ts, 239, 1)) +>snd : Symbol(snd, Decl(inferTypePredicates.ts, 249, 11)) + + let t: string = snd; // should ok +>t : Symbol(t, Decl(inferTypePredicates.ts, 251, 5)) +>snd : Symbol(snd, Decl(inferTypePredicates.ts, 249, 11)) + +} else { + snd; // type is number | Date +>snd : Symbol(snd, Decl(inferTypePredicates.ts, 249, 11)) +} + diff --git a/tests/baselines/reference/inferTypePredicates.types b/tests/baselines/reference/inferTypePredicates.types index 5252dd392f3..27206d90209 100644 --- a/tests/baselines/reference/inferTypePredicates.types +++ b/tests/baselines/reference/inferTypePredicates.types @@ -884,3 +884,41 @@ if (isNumOrStr(unk)) { >unk : string | number } +// A function can be a type predicate even if it throws. +function assertAndPredicate(x: string | number | Date) { +>assertAndPredicate : (x: string | number | Date) => x is string +>x : string | number | Date + + if (x instanceof Date) { +>x instanceof Date : boolean +>x : string | number | Date +>Date : DateConstructor + + throw new Error(); +>new Error() : Error +>Error : ErrorConstructor + } + return typeof x === 'string'; +>typeof x === 'string' : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : string | number +>'string' : "string" +} + +declare let snd: string | number | Date; +>snd : string | number | Date + +if (assertAndPredicate(snd)) { +>assertAndPredicate(snd) : boolean +>assertAndPredicate : (x: string | number | Date) => x is string +>snd : string | number | Date + + let t: string = snd; // should ok +>t : string +>snd : string + +} else { + snd; // type is number | Date +>snd : number | Date +} + diff --git a/tests/cases/compiler/inferTypePredicates.ts b/tests/cases/compiler/inferTypePredicates.ts index 519701c9d6b..388f38910f5 100644 --- a/tests/cases/compiler/inferTypePredicates.ts +++ b/tests/cases/compiler/inferTypePredicates.ts @@ -239,3 +239,18 @@ declare let unk: unknown; if (isNumOrStr(unk)) { let t: number | string = unk; // should ok } + +// A function can be a type predicate even if it throws. +function assertAndPredicate(x: string | number | Date) { + if (x instanceof Date) { + throw new Error(); + } + return typeof x === 'string'; +} + +declare let snd: string | number | Date; +if (assertAndPredicate(snd)) { + let t: string = snd; // should ok +} else { + snd; // type is number | Date +}