diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0d3b1ad3c0f96..8405985b27244 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11568,7 +11568,7 @@ namespace ts { let types: Type[]; const funcIsGenerator = !!func.asteriskToken; if (funcIsGenerator) { - types = checkAndAggregateYieldOperandTypes(func.body, contextualMapper); + types = checkAndAggregateYieldOperandTypes(func, contextualMapper); if (types.length === 0) { const iterableIteratorAny = createIterableIteratorType(anyType); if (compilerOptions.noImplicitAny) { @@ -11579,8 +11579,7 @@ namespace ts { } } else { - const hasImplicitReturn = !!(func.flags & NodeFlags.HasImplicitReturn); - types = checkAndAggregateReturnExpressionTypes(func.body, contextualMapper, isAsync, hasImplicitReturn); + types = checkAndAggregateReturnExpressionTypes(func, contextualMapper); if (!types) { return neverType; } @@ -11638,10 +11637,10 @@ namespace ts { } } - function checkAndAggregateYieldOperandTypes(body: Block, contextualMapper?: TypeMapper): Type[] { + function checkAndAggregateYieldOperandTypes(func: FunctionLikeDeclaration, contextualMapper: TypeMapper): Type[] { const aggregatedTypes: Type[] = []; - forEachYieldExpression(body, yieldExpression => { + forEachYieldExpression(func.body, yieldExpression => { const expr = yieldExpression.expression; if (expr) { let type = checkExpressionCached(expr, contextualMapper); @@ -11660,10 +11659,12 @@ namespace ts { return aggregatedTypes; } - function checkAndAggregateReturnExpressionTypes(body: Block, contextualMapper: TypeMapper, isAsync: boolean, hasImplicitReturn: boolean): Type[] { + function checkAndAggregateReturnExpressionTypes(func: FunctionLikeDeclaration, contextualMapper: TypeMapper): Type[] { + const isAsync = isAsyncFunctionLike(func); const aggregatedTypes: Type[] = []; - let hasOmittedExpressions = false; - forEachReturnStatement(body, returnStatement => { + let hasReturnWithNoExpression = !!(func.flags & NodeFlags.HasImplicitReturn); + let hasReturnOfTypeNever = false; + forEachReturnStatement(func.body, returnStatement => { const expr = returnStatement.expression; if (expr) { let type = checkExpressionCached(expr, contextualMapper); @@ -11672,20 +11673,24 @@ namespace ts { // Promise/A+ compatible implementation will always assimilate any foreign promise, so the // return type of the body should be unwrapped to its awaited type, which should be wrapped in // the native Promise type by the caller. - type = checkAwaitedType(type, body.parent, Diagnostics.Return_expression_in_async_function_does_not_have_a_valid_callable_then_member); + type = checkAwaitedType(type, func, Diagnostics.Return_expression_in_async_function_does_not_have_a_valid_callable_then_member); + } + if (type === neverType) { + hasReturnOfTypeNever = true; } - if (type !== neverType && !contains(aggregatedTypes, type)) { + else if (!contains(aggregatedTypes, type)) { aggregatedTypes.push(type); } } else { - hasOmittedExpressions = true; + hasReturnWithNoExpression = true; } }); - if (aggregatedTypes.length === 0 && !hasOmittedExpressions && !hasImplicitReturn) { + if (aggregatedTypes.length === 0 && !hasReturnWithNoExpression && (hasReturnOfTypeNever || + func.kind === SyntaxKind.FunctionExpression || func.kind === SyntaxKind.ArrowFunction)) { return undefined; } - if (strictNullChecks && aggregatedTypes.length && (hasOmittedExpressions || hasImplicitReturn)) { + if (strictNullChecks && aggregatedTypes.length && hasReturnWithNoExpression) { if (!contains(aggregatedTypes, undefinedType)) { aggregatedTypes.push(undefinedType); } diff --git a/tests/baselines/reference/controlFlowIteration.types b/tests/baselines/reference/controlFlowIteration.types index cefb250e01d84..52be501d68e8d 100644 --- a/tests/baselines/reference/controlFlowIteration.types +++ b/tests/baselines/reference/controlFlowIteration.types @@ -4,7 +4,7 @@ let cond: boolean; >cond : boolean function ff() { ->ff : () => never +>ff : () => void let x: string | undefined; >x : string | undefined diff --git a/tests/baselines/reference/duplicateLabel3.types b/tests/baselines/reference/duplicateLabel3.types index bcbe11beee304..920a077aa9ef2 100644 --- a/tests/baselines/reference/duplicateLabel3.types +++ b/tests/baselines/reference/duplicateLabel3.types @@ -7,7 +7,7 @@ while (true) { >true : boolean function f() { ->f : () => never +>f : () => void target: >target : any diff --git a/tests/baselines/reference/forStatementsMultipleValidDecl.types b/tests/baselines/reference/forStatementsMultipleValidDecl.types index ae5959f1bd32a..acb26f173120b 100644 --- a/tests/baselines/reference/forStatementsMultipleValidDecl.types +++ b/tests/baselines/reference/forStatementsMultipleValidDecl.types @@ -16,7 +16,7 @@ for (var x = undefined; ;) { } // new declaration space, making redeclaring x as a string valid function declSpace() { ->declSpace : () => never +>declSpace : () => void for (var x = 'this is a string'; ;) { } >x : string diff --git a/tests/baselines/reference/narrowingOfDottedNames.types b/tests/baselines/reference/narrowingOfDottedNames.types index 9ab15afbd08f5..697e080b661b3 100644 --- a/tests/baselines/reference/narrowingOfDottedNames.types +++ b/tests/baselines/reference/narrowingOfDottedNames.types @@ -42,7 +42,7 @@ function isB(x: any): x is B { } function f1(x: A | B) { ->f1 : (x: A | B) => never +>f1 : (x: A | B) => void >x : A | B >A : A >B : B @@ -78,7 +78,7 @@ function f1(x: A | B) { } function f2(x: A | B) { ->f2 : (x: A | B) => never +>f2 : (x: A | B) => void >x : A | B >A : A >B : B diff --git a/tests/baselines/reference/nestedBlockScopedBindings3.types b/tests/baselines/reference/nestedBlockScopedBindings3.types index f153a9a7cea57..37b89242f3e2c 100644 --- a/tests/baselines/reference/nestedBlockScopedBindings3.types +++ b/tests/baselines/reference/nestedBlockScopedBindings3.types @@ -1,6 +1,6 @@ === tests/cases/compiler/nestedBlockScopedBindings3.ts === function a0() { ->a0 : () => never +>a0 : () => void { for (let x = 0; x < 1; ) { >x : number @@ -26,7 +26,7 @@ function a0() { } function a1() { ->a1 : () => never +>a1 : () => void for (let x; x < 1;) { >x : any @@ -48,7 +48,7 @@ function a1() { } function a2() { ->a2 : () => never +>a2 : () => void for (let x; x < 1;) { >x : any diff --git a/tests/baselines/reference/nestedBlockScopedBindings4.types b/tests/baselines/reference/nestedBlockScopedBindings4.types index 5d0ed2a1d91c1..b38d61f3f4400 100644 --- a/tests/baselines/reference/nestedBlockScopedBindings4.types +++ b/tests/baselines/reference/nestedBlockScopedBindings4.types @@ -1,6 +1,6 @@ === tests/cases/compiler/nestedBlockScopedBindings4.ts === function a0() { ->a0 : () => never +>a0 : () => void for (let x; x < 1;) { >x : any @@ -28,7 +28,7 @@ function a0() { } function a1() { ->a1 : () => never +>a1 : () => void for (let x; x < 1;) { >x : any @@ -60,7 +60,7 @@ function a1() { } function a2() { ->a2 : () => never +>a2 : () => void for (let x; x < 1;) { >x : any @@ -93,7 +93,7 @@ function a2() { function a3() { ->a3 : () => never +>a3 : () => void for (let x; x < 1;) { >x : any diff --git a/tests/baselines/reference/nestedBlockScopedBindings6.types b/tests/baselines/reference/nestedBlockScopedBindings6.types index f6c918766ae1e..5c8c1fa68fadc 100644 --- a/tests/baselines/reference/nestedBlockScopedBindings6.types +++ b/tests/baselines/reference/nestedBlockScopedBindings6.types @@ -1,6 +1,6 @@ === tests/cases/compiler/nestedBlockScopedBindings6.ts === function a0() { ->a0 : () => never +>a0 : () => void for (let x of [1]) { >x : number @@ -27,7 +27,7 @@ function a0() { } function a1() { ->a1 : () => never +>a1 : () => void for (let x of [1]) { >x : number @@ -58,7 +58,7 @@ function a1() { } function a2() { ->a2 : () => never +>a2 : () => void for (let x of [1]) { >x : number @@ -89,7 +89,7 @@ function a2() { } function a3() { ->a3 : () => never +>a3 : () => void for (let x of [1]) { >x : number diff --git a/tests/baselines/reference/neverType.js b/tests/baselines/reference/neverType.js index 8c2c0293c21a2..56a1373903ed0 100644 --- a/tests/baselines/reference/neverType.js +++ b/tests/baselines/reference/neverType.js @@ -1,6 +1,11 @@ //// [neverType.ts] -function error(message: string) { + +function error(message: string): never { + throw new Error(message); +} + +function errorVoid(message: string) { throw new Error(message); } @@ -8,7 +13,19 @@ function fail() { return error("Something failed"); } -function infiniteLoop() { +function failOrThrow(shouldFail: boolean) { + if (shouldFail) { + return fail(); + } + throw new Error(); +} + +function infiniteLoop1() { + while (true) { + } +} + +function infiniteLoop2(): never { while (true) { } } @@ -33,6 +50,21 @@ function check(x: T | undefined) { return x || error("Undefined value"); } +class C { + void1() { + throw new Error(); + } + void2() { + while (true) {} + } + never1(): never { + throw new Error(); + } + never2(): never { + while (true) {} + } +} + function f1(x: string | number) { if (typeof x === "boolean") { x; // never @@ -47,13 +79,6 @@ function f2(x: string | number) { } } -function failOrThrow(shouldFail: boolean) { - if (shouldFail) { - return fail(); - } - throw new Error(); -} - function test(cb: () => string) { let s = cb(); return s; @@ -71,10 +96,23 @@ test(errorCallback); function error(message) { throw new Error(message); } +function errorVoid(message) { + throw new Error(message); +} function fail() { return error("Something failed"); } -function infiniteLoop() { +function failOrThrow(shouldFail) { + if (shouldFail) { + return fail(); + } + throw new Error(); +} +function infiniteLoop1() { + while (true) { + } +} +function infiniteLoop2() { while (true) { } } @@ -95,6 +133,23 @@ function move2(direction) { function check(x) { return x || error("Undefined value"); } +var C = (function () { + function C() { + } + C.prototype.void1 = function () { + throw new Error(); + }; + C.prototype.void2 = function () { + while (true) { } + }; + C.prototype.never1 = function () { + throw new Error(); + }; + C.prototype.never2 = function () { + while (true) { } + }; + return C; +}()); function f1(x) { if (typeof x === "boolean") { x; // never @@ -107,12 +162,6 @@ function f2(x) { } } } -function failOrThrow(shouldFail) { - if (shouldFail) { - return fail(); - } - throw new Error(); -} function test(cb) { var s = cb(); return s; @@ -126,13 +175,21 @@ test(errorCallback); //// [neverType.d.ts] declare function error(message: string): never; +declare function errorVoid(message: string): void; declare function fail(): never; -declare function infiniteLoop(): never; +declare function failOrThrow(shouldFail: boolean): never; +declare function infiniteLoop1(): void; +declare function infiniteLoop2(): never; declare function move1(direction: "up" | "down"): number; declare function move2(direction: "up" | "down"): number; declare function check(x: T | undefined): T; +declare class C { + void1(): void; + void2(): void; + never1(): never; + never2(): never; +} declare function f1(x: string | number): void; declare function f2(x: string | number): never; -declare function failOrThrow(shouldFail: boolean): never; declare function test(cb: () => string): string; declare let errorCallback: () => never; diff --git a/tests/baselines/reference/neverType.symbols b/tests/baselines/reference/neverType.symbols index e1c4e98c24ca3..4156934ddcc2a 100644 --- a/tests/baselines/reference/neverType.symbols +++ b/tests/baselines/reference/neverType.symbols @@ -1,34 +1,65 @@ === tests/cases/conformance/types/never/neverType.ts === -function error(message: string) { + +function error(message: string): never { >error : Symbol(error, Decl(neverType.ts, 0, 0)) ->message : Symbol(message, Decl(neverType.ts, 1, 15)) +>message : Symbol(message, Decl(neverType.ts, 2, 15)) + + throw new Error(message); +>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>message : Symbol(message, Decl(neverType.ts, 2, 15)) +} + +function errorVoid(message: string) { +>errorVoid : Symbol(errorVoid, Decl(neverType.ts, 4, 1)) +>message : Symbol(message, Decl(neverType.ts, 6, 19)) throw new Error(message); >Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) ->message : Symbol(message, Decl(neverType.ts, 1, 15)) +>message : Symbol(message, Decl(neverType.ts, 6, 19)) } function fail() { ->fail : Symbol(fail, Decl(neverType.ts, 3, 1)) +>fail : Symbol(fail, Decl(neverType.ts, 8, 1)) return error("Something failed"); >error : Symbol(error, Decl(neverType.ts, 0, 0)) } -function infiniteLoop() { ->infiniteLoop : Symbol(infiniteLoop, Decl(neverType.ts, 7, 1)) +function failOrThrow(shouldFail: boolean) { +>failOrThrow : Symbol(failOrThrow, Decl(neverType.ts, 12, 1)) +>shouldFail : Symbol(shouldFail, Decl(neverType.ts, 14, 21)) + + if (shouldFail) { +>shouldFail : Symbol(shouldFail, Decl(neverType.ts, 14, 21)) + + return fail(); +>fail : Symbol(fail, Decl(neverType.ts, 8, 1)) + } + throw new Error(); +>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +} + +function infiniteLoop1() { +>infiniteLoop1 : Symbol(infiniteLoop1, Decl(neverType.ts, 19, 1)) + + while (true) { + } +} + +function infiniteLoop2(): never { +>infiniteLoop2 : Symbol(infiniteLoop2, Decl(neverType.ts, 24, 1)) while (true) { } } function move1(direction: "up" | "down") { ->move1 : Symbol(move1, Decl(neverType.ts, 12, 1)) ->direction : Symbol(direction, Decl(neverType.ts, 14, 15)) +>move1 : Symbol(move1, Decl(neverType.ts, 29, 1)) +>direction : Symbol(direction, Decl(neverType.ts, 31, 15)) switch (direction) { ->direction : Symbol(direction, Decl(neverType.ts, 14, 15)) +>direction : Symbol(direction, Decl(neverType.ts, 31, 15)) case "up": return 1; @@ -40,98 +71,111 @@ function move1(direction: "up" | "down") { } function move2(direction: "up" | "down") { ->move2 : Symbol(move2, Decl(neverType.ts, 22, 1)) ->direction : Symbol(direction, Decl(neverType.ts, 24, 15)) +>move2 : Symbol(move2, Decl(neverType.ts, 39, 1)) +>direction : Symbol(direction, Decl(neverType.ts, 41, 15)) return direction === "up" ? 1 : ->direction : Symbol(direction, Decl(neverType.ts, 24, 15)) +>direction : Symbol(direction, Decl(neverType.ts, 41, 15)) direction === "down" ? -1 : ->direction : Symbol(direction, Decl(neverType.ts, 24, 15)) +>direction : Symbol(direction, Decl(neverType.ts, 41, 15)) error("Should never get here"); >error : Symbol(error, Decl(neverType.ts, 0, 0)) } function check(x: T | undefined) { ->check : Symbol(check, Decl(neverType.ts, 28, 1)) ->T : Symbol(T, Decl(neverType.ts, 30, 15)) ->x : Symbol(x, Decl(neverType.ts, 30, 18)) ->T : Symbol(T, Decl(neverType.ts, 30, 15)) +>check : Symbol(check, Decl(neverType.ts, 45, 1)) +>T : Symbol(T, Decl(neverType.ts, 47, 15)) +>x : Symbol(x, Decl(neverType.ts, 47, 18)) +>T : Symbol(T, Decl(neverType.ts, 47, 15)) return x || error("Undefined value"); ->x : Symbol(x, Decl(neverType.ts, 30, 18)) +>x : Symbol(x, Decl(neverType.ts, 47, 18)) >error : Symbol(error, Decl(neverType.ts, 0, 0)) } +class C { +>C : Symbol(C, Decl(neverType.ts, 49, 1)) + + void1() { +>void1 : Symbol(C.void1, Decl(neverType.ts, 51, 9)) + + throw new Error(); +>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + } + void2() { +>void2 : Symbol(C.void2, Decl(neverType.ts, 54, 5)) + + while (true) {} + } + never1(): never { +>never1 : Symbol(C.never1, Decl(neverType.ts, 57, 5)) + + throw new Error(); +>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + } + never2(): never { +>never2 : Symbol(C.never2, Decl(neverType.ts, 60, 5)) + + while (true) {} + } +} + function f1(x: string | number) { ->f1 : Symbol(f1, Decl(neverType.ts, 32, 1)) ->x : Symbol(x, Decl(neverType.ts, 34, 12)) +>f1 : Symbol(f1, Decl(neverType.ts, 64, 1)) +>x : Symbol(x, Decl(neverType.ts, 66, 12)) if (typeof x === "boolean") { ->x : Symbol(x, Decl(neverType.ts, 34, 12)) +>x : Symbol(x, Decl(neverType.ts, 66, 12)) x; // never ->x : Symbol(x, Decl(neverType.ts, 34, 12)) +>x : Symbol(x, Decl(neverType.ts, 66, 12)) } } function f2(x: string | number) { ->f2 : Symbol(f2, Decl(neverType.ts, 38, 1)) ->x : Symbol(x, Decl(neverType.ts, 40, 12)) +>f2 : Symbol(f2, Decl(neverType.ts, 70, 1)) +>x : Symbol(x, Decl(neverType.ts, 72, 12)) while (true) { if (typeof x === "boolean") { ->x : Symbol(x, Decl(neverType.ts, 40, 12)) +>x : Symbol(x, Decl(neverType.ts, 72, 12)) return x; // never ->x : Symbol(x, Decl(neverType.ts, 40, 12)) +>x : Symbol(x, Decl(neverType.ts, 72, 12)) } } } -function failOrThrow(shouldFail: boolean) { ->failOrThrow : Symbol(failOrThrow, Decl(neverType.ts, 46, 1)) ->shouldFail : Symbol(shouldFail, Decl(neverType.ts, 48, 21)) - - if (shouldFail) { ->shouldFail : Symbol(shouldFail, Decl(neverType.ts, 48, 21)) - - return fail(); ->fail : Symbol(fail, Decl(neverType.ts, 3, 1)) - } - throw new Error(); ->Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) -} - function test(cb: () => string) { ->test : Symbol(test, Decl(neverType.ts, 53, 1)) ->cb : Symbol(cb, Decl(neverType.ts, 55, 14)) +>test : Symbol(test, Decl(neverType.ts, 78, 1)) +>cb : Symbol(cb, Decl(neverType.ts, 80, 14)) let s = cb(); ->s : Symbol(s, Decl(neverType.ts, 56, 7)) ->cb : Symbol(cb, Decl(neverType.ts, 55, 14)) +>s : Symbol(s, Decl(neverType.ts, 81, 7)) +>cb : Symbol(cb, Decl(neverType.ts, 80, 14)) return s; ->s : Symbol(s, Decl(neverType.ts, 56, 7)) +>s : Symbol(s, Decl(neverType.ts, 81, 7)) } let errorCallback = () => error("Error callback"); ->errorCallback : Symbol(errorCallback, Decl(neverType.ts, 60, 3)) +>errorCallback : Symbol(errorCallback, Decl(neverType.ts, 85, 3)) >error : Symbol(error, Decl(neverType.ts, 0, 0)) test(() => "hello"); ->test : Symbol(test, Decl(neverType.ts, 53, 1)) +>test : Symbol(test, Decl(neverType.ts, 78, 1)) test(() => fail()); ->test : Symbol(test, Decl(neverType.ts, 53, 1)) ->fail : Symbol(fail, Decl(neverType.ts, 3, 1)) +>test : Symbol(test, Decl(neverType.ts, 78, 1)) +>fail : Symbol(fail, Decl(neverType.ts, 8, 1)) test(() => { throw new Error(); }) ->test : Symbol(test, Decl(neverType.ts, 53, 1)) +>test : Symbol(test, Decl(neverType.ts, 78, 1)) >Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) test(errorCallback); ->test : Symbol(test, Decl(neverType.ts, 53, 1)) ->errorCallback : Symbol(errorCallback, Decl(neverType.ts, 60, 3)) +>test : Symbol(test, Decl(neverType.ts, 78, 1)) +>errorCallback : Symbol(errorCallback, Decl(neverType.ts, 85, 3)) diff --git a/tests/baselines/reference/neverType.types b/tests/baselines/reference/neverType.types index e6b36bcbace71..5424f61d1ede5 100644 --- a/tests/baselines/reference/neverType.types +++ b/tests/baselines/reference/neverType.types @@ -1,6 +1,7 @@ === tests/cases/conformance/types/never/neverType.ts === -function error(message: string) { + +function error(message: string): never { >error : (message: string) => never >message : string @@ -10,6 +11,16 @@ function error(message: string) { >message : string } +function errorVoid(message: string) { +>errorVoid : (message: string) => void +>message : string + + throw new Error(message); +>new Error(message) : Error +>Error : ErrorConstructor +>message : string +} + function fail() { >fail : () => never @@ -19,8 +30,32 @@ function fail() { >"Something failed" : string } -function infiniteLoop() { ->infiniteLoop : () => never +function failOrThrow(shouldFail: boolean) { +>failOrThrow : (shouldFail: boolean) => never +>shouldFail : boolean + + if (shouldFail) { +>shouldFail : boolean + + return fail(); +>fail() : never +>fail : () => never + } + throw new Error(); +>new Error() : Error +>Error : ErrorConstructor +} + +function infiniteLoop1() { +>infiniteLoop1 : () => void + + while (true) { +>true : boolean + } +} + +function infiniteLoop2(): never { +>infiniteLoop2 : () => never while (true) { >true : boolean @@ -92,6 +127,37 @@ function check(x: T | undefined) { >"Undefined value" : string } +class C { +>C : C + + void1() { +>void1 : () => void + + throw new Error(); +>new Error() : Error +>Error : ErrorConstructor + } + void2() { +>void2 : () => void + + while (true) {} +>true : boolean + } + never1(): never { +>never1 : () => never + + throw new Error(); +>new Error() : Error +>Error : ErrorConstructor + } + never2(): never { +>never2 : () => never + + while (true) {} +>true : boolean + } +} + function f1(x: string | number) { >f1 : (x: string | number) => void >x : string | number @@ -126,22 +192,6 @@ function f2(x: string | number) { } } -function failOrThrow(shouldFail: boolean) { ->failOrThrow : (shouldFail: boolean) => never ->shouldFail : boolean - - if (shouldFail) { ->shouldFail : boolean - - return fail(); ->fail() : never ->fail : () => never - } - throw new Error(); ->new Error() : Error ->Error : ErrorConstructor -} - function test(cb: () => string) { >test : (cb: () => string) => string >cb : () => string diff --git a/tests/baselines/reference/parser_duplicateLabel3.types b/tests/baselines/reference/parser_duplicateLabel3.types index cc420085ef069..88ea435bf3e21 100644 --- a/tests/baselines/reference/parser_duplicateLabel3.types +++ b/tests/baselines/reference/parser_duplicateLabel3.types @@ -7,7 +7,7 @@ while (true) { >true : boolean function f() { ->f : () => never +>f : () => void target: >target : any diff --git a/tests/baselines/reference/throwInEnclosingStatements.types b/tests/baselines/reference/throwInEnclosingStatements.types index 26866ebb240af..c0a43ca38f548 100644 --- a/tests/baselines/reference/throwInEnclosingStatements.types +++ b/tests/baselines/reference/throwInEnclosingStatements.types @@ -1,7 +1,7 @@ === tests/cases/conformance/statements/throwStatements/throwInEnclosingStatements.ts === function fn(x) { ->fn : (x: any) => never +>fn : (x: any) => void >x : any throw x; @@ -78,7 +78,7 @@ class C { >T : T biz() { ->biz : () => never +>biz : () => void throw this.value; >this.value : T @@ -93,15 +93,15 @@ class C { } var aa = { ->aa : { id: number; biz(): never; } ->{ id:12, biz() { throw this; }} : { id: number; biz(): never; } +>aa : { id: number; biz(): void; } +>{ id:12, biz() { throw this; }} : { id: number; biz(): void; } id:12, >id : number >12 : number biz() { ->biz : () => never +>biz : () => void throw this; >this : any diff --git a/tests/cases/conformance/types/never/neverType.ts b/tests/cases/conformance/types/never/neverType.ts index d37528a022dd8..d58471d62a92b 100644 --- a/tests/cases/conformance/types/never/neverType.ts +++ b/tests/cases/conformance/types/never/neverType.ts @@ -1,7 +1,12 @@ // @strictNullChecks: true // @declaration: true -function error(message: string) { + +function error(message: string): never { + throw new Error(message); +} + +function errorVoid(message: string) { throw new Error(message); } @@ -9,7 +14,19 @@ function fail() { return error("Something failed"); } -function infiniteLoop() { +function failOrThrow(shouldFail: boolean) { + if (shouldFail) { + return fail(); + } + throw new Error(); +} + +function infiniteLoop1() { + while (true) { + } +} + +function infiniteLoop2(): never { while (true) { } } @@ -34,6 +51,21 @@ function check(x: T | undefined) { return x || error("Undefined value"); } +class C { + void1() { + throw new Error(); + } + void2() { + while (true) {} + } + never1(): never { + throw new Error(); + } + never2(): never { + while (true) {} + } +} + function f1(x: string | number) { if (typeof x === "boolean") { x; // never @@ -48,13 +80,6 @@ function f2(x: string | number) { } } -function failOrThrow(shouldFail: boolean) { - if (shouldFail) { - return fail(); - } - throw new Error(); -} - function test(cb: () => string) { let s = cb(); return s;