diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6a720d947df14..bf36b3abcfbc8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -120,9 +120,9 @@ namespace ts { const nullType = createIntrinsicType(TypeFlags.Null | nullableWideningFlags, "null"); const emptyArrayElementType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsUndefinedOrNull, "undefined"); const unknownType = createIntrinsicType(TypeFlags.Any, "unknown"); + const neverType = createIntrinsicType(TypeFlags.Never, "never"); const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - const nothingType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); const emptyGenericType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); emptyGenericType.instantiations = {}; @@ -2029,12 +2029,7 @@ namespace ts { writeUnionOrIntersectionType(type, flags); } else if (type.flags & TypeFlags.Anonymous) { - if (type === nothingType) { - writer.writeKeyword("nothing"); - } - else { - writeAnonymousType(type, flags); - } + writeAnonymousType(type, flags); } else if (type.flags & TypeFlags.StringLiteral) { writer.writeStringLiteral(`"${escapeString((type).text)}"`); @@ -3670,6 +3665,7 @@ namespace ts { case SyntaxKind.VoidKeyword: case SyntaxKind.UndefinedKeyword: case SyntaxKind.NullKeyword: + case SyntaxKind.NeverKeyword: case SyntaxKind.StringLiteralType: return true; case SyntaxKind.ArrayType: @@ -5005,7 +5001,7 @@ namespace ts { if (type.flags & TypeFlags.Undefined) typeSet.containsUndefined = true; if (type.flags & TypeFlags.Null) typeSet.containsNull = true; } - else if (type !== nothingType && !contains(typeSet, type)) { + else if (type !== neverType && !contains(typeSet, type)) { typeSet.push(type); } } @@ -5046,7 +5042,7 @@ namespace ts { // a named type that circularly references itself. function getUnionType(types: Type[], noSubtypeReduction?: boolean): Type { if (types.length === 0) { - return nothingType; + return neverType; } if (types.length === 1) { return types[0]; @@ -5066,7 +5062,7 @@ namespace ts { if (typeSet.length === 0) { return typeSet.containsNull ? nullType : typeSet.containsUndefined ? undefinedType : - nothingType; + neverType; } else if (typeSet.length === 1) { return typeSet[0]; @@ -5214,6 +5210,8 @@ namespace ts { return undefinedType; case SyntaxKind.NullKeyword: return nullType; + case SyntaxKind.NeverKeyword: + return neverType; case SyntaxKind.ThisType: case SyntaxKind.ThisKeyword: return getTypeFromThisTypeNode(node); @@ -5859,28 +5857,28 @@ namespace ts { return isIdenticalTo(source, target); } - if (target.flags & TypeFlags.Any) return Ternary.True; - if (source.flags & TypeFlags.Undefined) { - if (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void) || source === emptyArrayElementType) return Ternary.True; - } - if (source.flags & TypeFlags.Null) { - if (!strictNullChecks || target.flags & TypeFlags.Null) return Ternary.True; - } - if (source.flags & TypeFlags.Enum && target === numberType) return Ternary.True; - if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum) { - if (result = enumRelatedTo(source, target, reportErrors)) { - return result; + if (!(target.flags & TypeFlags.Never)) { + if (target.flags & TypeFlags.Any) return Ternary.True; + if (source.flags & TypeFlags.Undefined) { + if (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void) || source === emptyArrayElementType) return Ternary.True; + } + if (source.flags & TypeFlags.Null) { + if (!strictNullChecks || target.flags & TypeFlags.Null) return Ternary.True; + } + if (source.flags & TypeFlags.Enum && target === numberType) return Ternary.True; + if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum) { + if (result = enumRelatedTo(source, target, reportErrors)) { + return result; + } + } + if (source.flags & TypeFlags.StringLiteral && target === stringType) return Ternary.True; + if (relation === assignableRelation || relation === comparableRelation) { + if (source.flags & (TypeFlags.Any | TypeFlags.Never)) return Ternary.True; + if (source === numberType && target.flags & TypeFlags.Enum) return Ternary.True; + } + if (source.flags & TypeFlags.Boolean && target.flags & TypeFlags.Boolean) { + return Ternary.True; } - } - if (source.flags & TypeFlags.StringLiteral && target === stringType) return Ternary.True; - - if (relation === assignableRelation || relation === comparableRelation) { - if (isTypeAny(source)) return Ternary.True; - if (source === numberType && target.flags & TypeFlags.Enum) return Ternary.True; - } - - if (source.flags & TypeFlags.Boolean && target.flags & TypeFlags.Boolean) { - return Ternary.True; } if (source.flags & TypeFlags.FreshObjectLiteral) { @@ -7485,7 +7483,7 @@ namespace ts { function getTypeWithFacts(type: Type, include: TypeFacts) { if (!(type.flags & TypeFlags.Union)) { - return getTypeFacts(type) & include ? type : nothingType; + return getTypeFacts(type) & include ? type : neverType; } let firstType: Type; let types: Type[]; @@ -7502,7 +7500,7 @@ namespace ts { } } } - return firstType ? types ? getUnionType(types, /*noSubtypeReduction*/ true) : firstType : nothingType; + return firstType ? types ? getUnionType(types, /*noSubtypeReduction*/ true) : firstType : neverType; } function getTypeWithDefault(type: Type, defaultExpression: Expression) { @@ -7622,7 +7620,7 @@ namespace ts { const visitedFlowStart = visitedFlowCount; const result = getTypeAtFlowNode(reference.flowNode); visitedFlowCount = visitedFlowStart; - if (reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(result, TypeFacts.NEUndefinedOrNull) === nothingType) { + if (reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(result, TypeFacts.NEUndefinedOrNull) === neverType) { return declaredType; } return result; @@ -7710,7 +7708,7 @@ namespace ts { function getTypeAtFlowCondition(flow: FlowCondition) { let type = getTypeAtFlowNode(flow.antecedent); - if (type !== nothingType) { + if (type !== neverType) { // If we have an antecedent type (meaning we're reachable in some way), we first // attempt to narrow the antecedent type. If that produces the nothing type, then // we take the type guard as an indication that control could reach here in a @@ -7720,7 +7718,7 @@ namespace ts { // narrow that. const assumeTrue = (flow.flags & FlowFlags.TrueCondition) !== 0; type = narrowType(type, flow.expression, assumeTrue); - if (type === nothingType) { + if (type === neverType) { type = narrowType(declaredType, flow.expression, assumeTrue); } } @@ -7942,7 +7940,7 @@ namespace ts { const targetType = type.flags & TypeFlags.TypeParameter ? getApparentType(type) : type; return isTypeAssignableTo(candidate, targetType) ? candidate : isTypeAssignableTo(type, candidate) ? type : - nothingType; + neverType; } function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { @@ -11547,6 +11545,9 @@ namespace ts { else { const hasImplicitReturn = !!(func.flags & NodeFlags.HasImplicitReturn); types = checkAndAggregateReturnExpressionTypes(func.body, contextualMapper, isAsync, hasImplicitReturn); + if (!types) { + return neverType; + } if (types.length === 0) { if (isAsync) { // For an async function, the return type will not be void, but rather a Promise for void. @@ -11555,12 +11556,9 @@ namespace ts { error(func, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type); return unknownType; } - return promiseType; } - else { - return voidType; - } + return voidType; } } // When yield/return statements are contextually typed we allow the return type to be a union type. @@ -11640,7 +11638,7 @@ namespace ts { // 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); } - if (!contains(aggregatedTypes, type)) { + if (type !== neverType && !contains(aggregatedTypes, type)) { aggregatedTypes.push(type); } } @@ -11648,6 +11646,9 @@ namespace ts { hasOmittedExpressions = true; } }); + if (aggregatedTypes.length === 0 && !hasOmittedExpressions && !hasImplicitReturn) { + return undefined; + } if (strictNullChecks && aggregatedTypes.length && (hasOmittedExpressions || hasImplicitReturn)) { if (!contains(aggregatedTypes, undefinedType)) { aggregatedTypes.push(undefinedType); @@ -11683,7 +11684,10 @@ namespace ts { const hasExplicitReturn = func.flags & NodeFlags.HasExplicitReturn; - if (returnType && !hasExplicitReturn) { + if (returnType === neverType) { + error(func.type, Diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point); + } + else if (returnType && !hasExplicitReturn) { // minimal check: function has syntactic return type annotation and no explicit return statements in the body // this function does not conform to the specification. // NOTE: having returnType !== undefined is a precondition for entering this branch so func.type will always be present @@ -14747,7 +14751,7 @@ namespace ts { arrayType = getUnionType(filter((arrayOrStringType as UnionType).types, t => !(t.flags & TypeFlags.StringLike))); } else if (arrayOrStringType.flags & TypeFlags.StringLike) { - arrayType = nothingType; + arrayType = neverType; } const hasStringConstituent = arrayOrStringType !== arrayType; let reportedError = false; @@ -14759,7 +14763,7 @@ namespace ts { // Now that we've removed all the StringLike types, if no constituents remain, then the entire // arrayOrStringType was a string. - if (arrayType === nothingType) { + if (arrayType === neverType) { return stringType; } } @@ -14820,7 +14824,7 @@ namespace ts { if (func) { const signature = getSignatureFromDeclaration(func); const returnType = getReturnTypeOfSignature(signature); - if (strictNullChecks || node.expression) { + if (strictNullChecks || node.expression || returnType === neverType) { const exprType = node.expression ? checkExpressionCached(node.expression) : undefinedType; if (func.asteriskToken) { diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index c24135ba52ec5..9e4f789674532 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -395,6 +395,7 @@ namespace ts { case SyntaxKind.VoidKeyword: case SyntaxKind.UndefinedKeyword: case SyntaxKind.NullKeyword: + case SyntaxKind.NeverKeyword: case SyntaxKind.ThisType: case SyntaxKind.StringLiteralType: return writeTextOfNode(currentText, type); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 899b4292f04d1..4c9de081ac52f 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1751,6 +1751,10 @@ "category": "Error", "code": 2533 }, + "A function returning 'never' cannot have a reachable end point.": { + "category": "Error", + "code": 2534 + }, "JSX element attributes type '{0}' may not be a union type.": { "category": "Error", "code": 2600 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index daebf8a930be3..b60082969db6f 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2368,6 +2368,7 @@ namespace ts { case SyntaxKind.BooleanKeyword: case SyntaxKind.SymbolKeyword: case SyntaxKind.UndefinedKeyword: + case SyntaxKind.NeverKeyword: // If these are followed by a dot, then parse these out as a dotted type reference instead. const node = tryParse(parseKeywordAndNoDot); return node || parseTypeReference(); @@ -2410,6 +2411,7 @@ namespace ts { case SyntaxKind.NullKeyword: case SyntaxKind.ThisKeyword: case SyntaxKind.TypeOfKeyword: + case SyntaxKind.NeverKeyword: case SyntaxKind.OpenBraceToken: case SyntaxKind.OpenBracketToken: case SyntaxKind.LessThanToken: diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 8979814a7a2a6..1a2748b38b15f 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -91,6 +91,7 @@ namespace ts { "let": SyntaxKind.LetKeyword, "module": SyntaxKind.ModuleKeyword, "namespace": SyntaxKind.NamespaceKeyword, + "never": SyntaxKind.NeverKeyword, "new": SyntaxKind.NewKeyword, "null": SyntaxKind.NullKeyword, "number": SyntaxKind.NumberKeyword, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 777141b45fbd6..b23c2fa3a6763 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -164,6 +164,7 @@ namespace ts { IsKeyword, ModuleKeyword, NamespaceKeyword, + NeverKeyword, ReadonlyKeyword, RequireKeyword, NumberKeyword, @@ -2170,11 +2171,12 @@ namespace ts { ESSymbol = 0x01000000, // Type of symbol primitive introduced in ES6 ThisType = 0x02000000, // This type ObjectLiteralPatternWithComputedProperties = 0x04000000, // Object literal type implied by binding pattern has computed properties + Never = 0x08000000, // Never type /* @internal */ Nullable = Undefined | Null, /* @internal */ - Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null, + Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null | Never, /* @internal */ Primitive = String | Number | Boolean | ESSymbol | Void | Undefined | Null | StringLiteral | Enum, StringLike = String | StringLiteral, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 42ba6b9d0fcfa..9a86e223ebd4b 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -613,6 +613,7 @@ namespace ts { case SyntaxKind.BooleanKeyword: case SyntaxKind.SymbolKeyword: case SyntaxKind.UndefinedKeyword: + case SyntaxKind.NeverKeyword: return true; case SyntaxKind.VoidKeyword: return node.parent.kind !== SyntaxKind.VoidExpression; diff --git a/tests/baselines/reference/controlFlowIteration.types b/tests/baselines/reference/controlFlowIteration.types index 52be501d68e8d..cefb250e01d84 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 : () => void +>ff : () => never let x: string | undefined; >x : string | undefined diff --git a/tests/baselines/reference/duplicateLabel3.types b/tests/baselines/reference/duplicateLabel3.types index 920a077aa9ef2..bcbe11beee304 100644 --- a/tests/baselines/reference/duplicateLabel3.types +++ b/tests/baselines/reference/duplicateLabel3.types @@ -7,7 +7,7 @@ while (true) { >true : boolean function f() { ->f : () => void +>f : () => never target: >target : any diff --git a/tests/baselines/reference/forStatementsMultipleValidDecl.types b/tests/baselines/reference/forStatementsMultipleValidDecl.types index acb26f173120b..ae5959f1bd32a 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 : () => void +>declSpace : () => never for (var x = 'this is a string'; ;) { } >x : string diff --git a/tests/baselines/reference/instanceOfAssignability.types b/tests/baselines/reference/instanceOfAssignability.types index 0a9e1a3e99671..70d068fb0cc46 100644 --- a/tests/baselines/reference/instanceOfAssignability.types +++ b/tests/baselines/reference/instanceOfAssignability.types @@ -133,8 +133,8 @@ function fn5(x: Derived1) { // 1.5: y: Derived1 // Want: ??? let y = x; ->y : nothing ->x : nothing +>y : never +>x : never } } diff --git a/tests/baselines/reference/narrowingOfDottedNames.types b/tests/baselines/reference/narrowingOfDottedNames.types index 697e080b661b3..9ab15afbd08f5 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) => void +>f1 : (x: A | B) => never >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) => void +>f2 : (x: A | B) => never >x : A | B >A : A >B : B diff --git a/tests/baselines/reference/nestedBlockScopedBindings3.types b/tests/baselines/reference/nestedBlockScopedBindings3.types index 37b89242f3e2c..f153a9a7cea57 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 : () => void +>a0 : () => never { for (let x = 0; x < 1; ) { >x : number @@ -26,7 +26,7 @@ function a0() { } function a1() { ->a1 : () => void +>a1 : () => never for (let x; x < 1;) { >x : any @@ -48,7 +48,7 @@ function a1() { } function a2() { ->a2 : () => void +>a2 : () => never for (let x; x < 1;) { >x : any diff --git a/tests/baselines/reference/nestedBlockScopedBindings4.types b/tests/baselines/reference/nestedBlockScopedBindings4.types index b38d61f3f4400..5d0ed2a1d91c1 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 : () => void +>a0 : () => never for (let x; x < 1;) { >x : any @@ -28,7 +28,7 @@ function a0() { } function a1() { ->a1 : () => void +>a1 : () => never for (let x; x < 1;) { >x : any @@ -60,7 +60,7 @@ function a1() { } function a2() { ->a2 : () => void +>a2 : () => never for (let x; x < 1;) { >x : any @@ -93,7 +93,7 @@ function a2() { function a3() { ->a3 : () => void +>a3 : () => never for (let x; x < 1;) { >x : any diff --git a/tests/baselines/reference/nestedBlockScopedBindings6.types b/tests/baselines/reference/nestedBlockScopedBindings6.types index 5c8c1fa68fadc..f6c918766ae1e 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 : () => void +>a0 : () => never for (let x of [1]) { >x : number @@ -27,7 +27,7 @@ function a0() { } function a1() { ->a1 : () => void +>a1 : () => never for (let x of [1]) { >x : number @@ -58,7 +58,7 @@ function a1() { } function a2() { ->a2 : () => void +>a2 : () => never for (let x of [1]) { >x : number @@ -89,7 +89,7 @@ function a2() { } function a3() { ->a3 : () => void +>a3 : () => never for (let x of [1]) { >x : number diff --git a/tests/baselines/reference/neverType.js b/tests/baselines/reference/neverType.js new file mode 100644 index 0000000000000..8c2c0293c21a2 --- /dev/null +++ b/tests/baselines/reference/neverType.js @@ -0,0 +1,138 @@ +//// [neverType.ts] + +function error(message: string) { + throw new Error(message); +} + +function fail() { + return error("Something failed"); +} + +function infiniteLoop() { + while (true) { + } +} + +function move1(direction: "up" | "down") { + switch (direction) { + case "up": + return 1; + case "down": + return -1; + } + return error("Should never get here"); +} + +function move2(direction: "up" | "down") { + return direction === "up" ? 1 : + direction === "down" ? -1 : + error("Should never get here"); +} + +function check(x: T | undefined) { + return x || error("Undefined value"); +} + +function f1(x: string | number) { + if (typeof x === "boolean") { + x; // never + } +} + +function f2(x: string | number) { + while (true) { + if (typeof x === "boolean") { + return x; // never + } + } +} + +function failOrThrow(shouldFail: boolean) { + if (shouldFail) { + return fail(); + } + throw new Error(); +} + +function test(cb: () => string) { + let s = cb(); + return s; +} + +let errorCallback = () => error("Error callback"); + +test(() => "hello"); +test(() => fail()); +test(() => { throw new Error(); }) +test(errorCallback); + + +//// [neverType.js] +function error(message) { + throw new Error(message); +} +function fail() { + return error("Something failed"); +} +function infiniteLoop() { + while (true) { + } +} +function move1(direction) { + switch (direction) { + case "up": + return 1; + case "down": + return -1; + } + return error("Should never get here"); +} +function move2(direction) { + return direction === "up" ? 1 : + direction === "down" ? -1 : + error("Should never get here"); +} +function check(x) { + return x || error("Undefined value"); +} +function f1(x) { + if (typeof x === "boolean") { + x; // never + } +} +function f2(x) { + while (true) { + if (typeof x === "boolean") { + return x; // never + } + } +} +function failOrThrow(shouldFail) { + if (shouldFail) { + return fail(); + } + throw new Error(); +} +function test(cb) { + var s = cb(); + return s; +} +var errorCallback = function () { return error("Error callback"); }; +test(function () { return "hello"; }); +test(function () { return fail(); }); +test(function () { throw new Error(); }); +test(errorCallback); + + +//// [neverType.d.ts] +declare function error(message: string): never; +declare function fail(): never; +declare function infiniteLoop(): never; +declare function move1(direction: "up" | "down"): number; +declare function move2(direction: "up" | "down"): number; +declare function check(x: T | undefined): T; +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 new file mode 100644 index 0000000000000..e1c4e98c24ca3 --- /dev/null +++ b/tests/baselines/reference/neverType.symbols @@ -0,0 +1,137 @@ +=== tests/cases/conformance/types/never/neverType.ts === + +function error(message: string) { +>error : Symbol(error, Decl(neverType.ts, 0, 0)) +>message : Symbol(message, Decl(neverType.ts, 1, 15)) + + throw new Error(message); +>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>message : Symbol(message, Decl(neverType.ts, 1, 15)) +} + +function fail() { +>fail : Symbol(fail, Decl(neverType.ts, 3, 1)) + + return error("Something failed"); +>error : Symbol(error, Decl(neverType.ts, 0, 0)) +} + +function infiniteLoop() { +>infiniteLoop : Symbol(infiniteLoop, Decl(neverType.ts, 7, 1)) + + while (true) { + } +} + +function move1(direction: "up" | "down") { +>move1 : Symbol(move1, Decl(neverType.ts, 12, 1)) +>direction : Symbol(direction, Decl(neverType.ts, 14, 15)) + + switch (direction) { +>direction : Symbol(direction, Decl(neverType.ts, 14, 15)) + + case "up": + return 1; + case "down": + return -1; + } + return error("Should never get here"); +>error : Symbol(error, Decl(neverType.ts, 0, 0)) +} + +function move2(direction: "up" | "down") { +>move2 : Symbol(move2, Decl(neverType.ts, 22, 1)) +>direction : Symbol(direction, Decl(neverType.ts, 24, 15)) + + return direction === "up" ? 1 : +>direction : Symbol(direction, Decl(neverType.ts, 24, 15)) + + direction === "down" ? -1 : +>direction : Symbol(direction, Decl(neverType.ts, 24, 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)) + + return x || error("Undefined value"); +>x : Symbol(x, Decl(neverType.ts, 30, 18)) +>error : Symbol(error, Decl(neverType.ts, 0, 0)) +} + +function f1(x: string | number) { +>f1 : Symbol(f1, Decl(neverType.ts, 32, 1)) +>x : Symbol(x, Decl(neverType.ts, 34, 12)) + + if (typeof x === "boolean") { +>x : Symbol(x, Decl(neverType.ts, 34, 12)) + + x; // never +>x : Symbol(x, Decl(neverType.ts, 34, 12)) + } +} + +function f2(x: string | number) { +>f2 : Symbol(f2, Decl(neverType.ts, 38, 1)) +>x : Symbol(x, Decl(neverType.ts, 40, 12)) + + while (true) { + if (typeof x === "boolean") { +>x : Symbol(x, Decl(neverType.ts, 40, 12)) + + return x; // never +>x : Symbol(x, Decl(neverType.ts, 40, 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)) + + let s = cb(); +>s : Symbol(s, Decl(neverType.ts, 56, 7)) +>cb : Symbol(cb, Decl(neverType.ts, 55, 14)) + + return s; +>s : Symbol(s, Decl(neverType.ts, 56, 7)) +} + +let errorCallback = () => error("Error callback"); +>errorCallback : Symbol(errorCallback, Decl(neverType.ts, 60, 3)) +>error : Symbol(error, Decl(neverType.ts, 0, 0)) + +test(() => "hello"); +>test : Symbol(test, Decl(neverType.ts, 53, 1)) + +test(() => fail()); +>test : Symbol(test, Decl(neverType.ts, 53, 1)) +>fail : Symbol(fail, Decl(neverType.ts, 3, 1)) + +test(() => { throw new Error(); }) +>test : Symbol(test, Decl(neverType.ts, 53, 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)) + diff --git a/tests/baselines/reference/neverType.types b/tests/baselines/reference/neverType.types new file mode 100644 index 0000000000000..e6b36bcbace71 --- /dev/null +++ b/tests/baselines/reference/neverType.types @@ -0,0 +1,189 @@ +=== tests/cases/conformance/types/never/neverType.ts === + +function error(message: string) { +>error : (message: string) => never +>message : string + + throw new Error(message); +>new Error(message) : Error +>Error : ErrorConstructor +>message : string +} + +function fail() { +>fail : () => never + + return error("Something failed"); +>error("Something failed") : never +>error : (message: string) => never +>"Something failed" : string +} + +function infiniteLoop() { +>infiniteLoop : () => never + + while (true) { +>true : boolean + } +} + +function move1(direction: "up" | "down") { +>move1 : (direction: "up" | "down") => number +>direction : "up" | "down" + + switch (direction) { +>direction : "up" | "down" + + case "up": +>"up" : string + + return 1; +>1 : number + + case "down": +>"down" : string + + return -1; +>-1 : number +>1 : number + } + return error("Should never get here"); +>error("Should never get here") : never +>error : (message: string) => never +>"Should never get here" : string +} + +function move2(direction: "up" | "down") { +>move2 : (direction: "up" | "down") => number +>direction : "up" | "down" + + return direction === "up" ? 1 : +>direction === "up" ? 1 : direction === "down" ? -1 : error("Should never get here") : number +>direction === "up" : boolean +>direction : "up" | "down" +>"up" : string +>1 : number + + direction === "down" ? -1 : +>direction === "down" ? -1 : error("Should never get here") : number +>direction === "down" : boolean +>direction : "up" | "down" +>"down" : string +>-1 : number +>1 : number + + error("Should never get here"); +>error("Should never get here") : never +>error : (message: string) => never +>"Should never get here" : string +} + +function check(x: T | undefined) { +>check : (x: T | undefined) => T +>T : T +>x : T | undefined +>T : T + + return x || error("Undefined value"); +>x || error("Undefined value") : T +>x : T | undefined +>error("Undefined value") : never +>error : (message: string) => never +>"Undefined value" : string +} + +function f1(x: string | number) { +>f1 : (x: string | number) => void +>x : string | number + + if (typeof x === "boolean") { +>typeof x === "boolean" : boolean +>typeof x : string +>x : string | number +>"boolean" : string + + x; // never +>x : never + } +} + +function f2(x: string | number) { +>f2 : (x: string | number) => never +>x : string | number + + while (true) { +>true : boolean + + if (typeof x === "boolean") { +>typeof x === "boolean" : boolean +>typeof x : string +>x : string | number +>"boolean" : string + + return x; // never +>x : 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 test(cb: () => string) { +>test : (cb: () => string) => string +>cb : () => string + + let s = cb(); +>s : string +>cb() : string +>cb : () => string + + return s; +>s : string +} + +let errorCallback = () => error("Error callback"); +>errorCallback : () => never +>() => error("Error callback") : () => never +>error("Error callback") : never +>error : (message: string) => never +>"Error callback" : string + +test(() => "hello"); +>test(() => "hello") : string +>test : (cb: () => string) => string +>() => "hello" : () => string +>"hello" : string + +test(() => fail()); +>test(() => fail()) : string +>test : (cb: () => string) => string +>() => fail() : () => never +>fail() : never +>fail : () => never + +test(() => { throw new Error(); }) +>test(() => { throw new Error(); }) : string +>test : (cb: () => string) => string +>() => { throw new Error(); } : () => never +>new Error() : Error +>Error : ErrorConstructor + +test(errorCallback); +>test(errorCallback) : string +>test : (cb: () => string) => string +>errorCallback : () => never + diff --git a/tests/baselines/reference/neverTypeErrors1.errors.txt b/tests/baselines/reference/neverTypeErrors1.errors.txt new file mode 100644 index 0000000000000..8fd6f9c924eaa --- /dev/null +++ b/tests/baselines/reference/neverTypeErrors1.errors.txt @@ -0,0 +1,50 @@ +tests/cases/conformance/types/never/neverTypeErrors1.ts(3,5): error TS2322: Type 'number' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors1.ts(4,5): error TS2322: Type 'string' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors1.ts(5,5): error TS2322: Type 'boolean' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors1.ts(6,5): error TS2322: Type 'undefined' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors1.ts(7,5): error TS2322: Type 'null' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors1.ts(8,5): error TS2322: Type '{}' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors1.ts(12,5): error TS2322: Type 'undefined' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors1.ts(16,12): error TS2322: Type 'number' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors1.ts(19,16): error TS2534: A function returning 'never' cannot have a reachable end point. + + +==== tests/cases/conformance/types/never/neverTypeErrors1.ts (9 errors) ==== + function f1() { + let x: never; + x = 1; + ~ +!!! error TS2322: Type 'number' is not assignable to type 'never'. + x = "abc"; + ~ +!!! error TS2322: Type 'string' is not assignable to type 'never'. + x = false; + ~ +!!! error TS2322: Type 'boolean' is not assignable to type 'never'. + x = undefined; + ~ +!!! error TS2322: Type 'undefined' is not assignable to type 'never'. + x = null; + ~ +!!! error TS2322: Type 'null' is not assignable to type 'never'. + x = {}; + ~ +!!! error TS2322: Type '{}' is not assignable to type 'never'. + } + + function f2(): never { + return; + ~~~~~~~ +!!! error TS2322: Type 'undefined' is not assignable to type 'never'. + } + + function f3(): never { + return 1; + ~ +!!! error TS2322: Type 'number' is not assignable to type 'never'. + } + + function f4(): never { + ~~~~~ +!!! error TS2534: A function returning 'never' cannot have a reachable end point. + } \ No newline at end of file diff --git a/tests/baselines/reference/neverTypeErrors1.js b/tests/baselines/reference/neverTypeErrors1.js new file mode 100644 index 0000000000000..81b3f8f9cdb11 --- /dev/null +++ b/tests/baselines/reference/neverTypeErrors1.js @@ -0,0 +1,40 @@ +//// [neverTypeErrors1.ts] +function f1() { + let x: never; + x = 1; + x = "abc"; + x = false; + x = undefined; + x = null; + x = {}; +} + +function f2(): never { + return; +} + +function f3(): never { + return 1; +} + +function f4(): never { +} + +//// [neverTypeErrors1.js] +function f1() { + var x; + x = 1; + x = "abc"; + x = false; + x = undefined; + x = null; + x = {}; +} +function f2() { + return; +} +function f3() { + return 1; +} +function f4() { +} diff --git a/tests/baselines/reference/neverTypeErrors2.errors.txt b/tests/baselines/reference/neverTypeErrors2.errors.txt new file mode 100644 index 0000000000000..c6292657ad178 --- /dev/null +++ b/tests/baselines/reference/neverTypeErrors2.errors.txt @@ -0,0 +1,51 @@ +tests/cases/conformance/types/never/neverTypeErrors2.ts(4,5): error TS2322: Type 'number' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors2.ts(5,5): error TS2322: Type 'string' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors2.ts(6,5): error TS2322: Type 'boolean' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors2.ts(7,5): error TS2322: Type 'undefined' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors2.ts(8,5): error TS2322: Type 'null' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors2.ts(9,5): error TS2322: Type '{}' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors2.ts(13,5): error TS2322: Type 'undefined' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors2.ts(17,12): error TS2322: Type 'number' is not assignable to type 'never'. +tests/cases/conformance/types/never/neverTypeErrors2.ts(20,16): error TS2534: A function returning 'never' cannot have a reachable end point. + + +==== tests/cases/conformance/types/never/neverTypeErrors2.ts (9 errors) ==== + + function f1() { + let x: never; + x = 1; + ~ +!!! error TS2322: Type 'number' is not assignable to type 'never'. + x = "abc"; + ~ +!!! error TS2322: Type 'string' is not assignable to type 'never'. + x = false; + ~ +!!! error TS2322: Type 'boolean' is not assignable to type 'never'. + x = undefined; + ~ +!!! error TS2322: Type 'undefined' is not assignable to type 'never'. + x = null; + ~ +!!! error TS2322: Type 'null' is not assignable to type 'never'. + x = {}; + ~ +!!! error TS2322: Type '{}' is not assignable to type 'never'. + } + + function f2(): never { + return; + ~~~~~~~ +!!! error TS2322: Type 'undefined' is not assignable to type 'never'. + } + + function f3(): never { + return 1; + ~ +!!! error TS2322: Type 'number' is not assignable to type 'never'. + } + + function f4(): never { + ~~~~~ +!!! error TS2534: A function returning 'never' cannot have a reachable end point. + } \ No newline at end of file diff --git a/tests/baselines/reference/neverTypeErrors2.js b/tests/baselines/reference/neverTypeErrors2.js new file mode 100644 index 0000000000000..18c92922bc1b7 --- /dev/null +++ b/tests/baselines/reference/neverTypeErrors2.js @@ -0,0 +1,41 @@ +//// [neverTypeErrors2.ts] + +function f1() { + let x: never; + x = 1; + x = "abc"; + x = false; + x = undefined; + x = null; + x = {}; +} + +function f2(): never { + return; +} + +function f3(): never { + return 1; +} + +function f4(): never { +} + +//// [neverTypeErrors2.js] +function f1() { + var x; + x = 1; + x = "abc"; + x = false; + x = undefined; + x = null; + x = {}; +} +function f2() { + return; +} +function f3() { + return 1; +} +function f4() { +} diff --git a/tests/baselines/reference/parser_duplicateLabel3.types b/tests/baselines/reference/parser_duplicateLabel3.types index 88ea435bf3e21..cc420085ef069 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 : () => void +>f : () => never target: >target : any diff --git a/tests/baselines/reference/promiseVoidErrorCallback.types b/tests/baselines/reference/promiseVoidErrorCallback.types index 82b248f64bdb8..b536ab089bdb6 100644 --- a/tests/baselines/reference/promiseVoidErrorCallback.types +++ b/tests/baselines/reference/promiseVoidErrorCallback.types @@ -63,7 +63,7 @@ var x3 = f1() .then(f2, (e: Error) => { >then : { (onfulfilled?: (value: T1) => TResult | PromiseLike, onrejected?: (reason: any) => TResult | PromiseLike): Promise; (onfulfilled?: (value: T1) => TResult | PromiseLike, onrejected?: (reason: any) => void): Promise; } >f2 : (x: T1) => T2 ->(e: Error) => { throw e;} : (e: Error) => void +>(e: Error) => { throw e;} : (e: Error) => never >e : Error >Error : Error diff --git a/tests/baselines/reference/stringLiteralTypesAsTags01.types b/tests/baselines/reference/stringLiteralTypesAsTags01.types index 9f273cf93a90d..7b8ac0a8c02b8 100644 --- a/tests/baselines/reference/stringLiteralTypesAsTags01.types +++ b/tests/baselines/reference/stringLiteralTypesAsTags01.types @@ -116,6 +116,6 @@ if (!hasKind(x, "B")) { } else { let d = x; ->d : nothing ->x : nothing +>d : never +>x : never } diff --git a/tests/baselines/reference/stringLiteralTypesAsTags02.types b/tests/baselines/reference/stringLiteralTypesAsTags02.types index bcfa74ef55fa3..290402cd299cb 100644 --- a/tests/baselines/reference/stringLiteralTypesAsTags02.types +++ b/tests/baselines/reference/stringLiteralTypesAsTags02.types @@ -110,6 +110,6 @@ if (!hasKind(x, "B")) { } else { let d = x; ->d : nothing ->x : nothing +>d : never +>x : never } diff --git a/tests/baselines/reference/stringLiteralTypesAsTags03.types b/tests/baselines/reference/stringLiteralTypesAsTags03.types index c7fdfc7152e83..9d004982dda07 100644 --- a/tests/baselines/reference/stringLiteralTypesAsTags03.types +++ b/tests/baselines/reference/stringLiteralTypesAsTags03.types @@ -113,6 +113,6 @@ if (!hasKind(x, "B")) { } else { let d = x; ->d : nothing ->x : nothing +>d : never +>x : never } diff --git a/tests/baselines/reference/throwInEnclosingStatements.types b/tests/baselines/reference/throwInEnclosingStatements.types index 32f0fb093bcd9..26866ebb240af 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) => void +>fn : (x: any) => never >x : any throw x; @@ -9,7 +9,7 @@ function fn(x) { } (x: T) => { throw x; } ->(x: T) => { throw x; } : (x: T) => void +>(x: T) => { throw x; } : (x: T) => never >T : T >x : T >T : T @@ -78,7 +78,7 @@ class C { >T : T biz() { ->biz : () => void +>biz : () => never throw this.value; >this.value : T @@ -93,15 +93,15 @@ class C { } var aa = { ->aa : { id: number; biz(): void; } ->{ id:12, biz() { throw this; }} : { id: number; biz(): void; } +>aa : { id: number; biz(): never; } +>{ id:12, biz() { throw this; }} : { id: number; biz(): never; } id:12, >id : number >12 : number biz() { ->biz : () => void +>biz : () => never throw this; >this : any diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.types b/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.types index 564c6ceaa72a8..7a4b279b57254 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.types +++ b/tests/baselines/reference/typeGuardOfFormTypeOfBoolean.types @@ -121,7 +121,7 @@ if (typeof strOrNum === "boolean") { let z1: {} = strOrNum; // {} >z1 : {} ->strOrNum : nothing +>strOrNum : never } else { let z2: string | number = strOrNum; // string | number @@ -215,6 +215,6 @@ if (typeof strOrNum !== "boolean") { else { let z2: {} = strOrNum; // {} >z2 : {} ->strOrNum : nothing +>strOrNum : never } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfNumber.types b/tests/baselines/reference/typeGuardOfFormTypeOfNumber.types index 51326c68cd960..c6a5615e75a8c 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfNumber.types +++ b/tests/baselines/reference/typeGuardOfFormTypeOfNumber.types @@ -120,7 +120,7 @@ if (typeof strOrBool === "number") { let y1: {} = strOrBool; // {} >y1 : {} ->strOrBool : nothing +>strOrBool : never } else { let y2: string | boolean = strOrBool; // string | boolean @@ -212,6 +212,6 @@ if (typeof strOrBool !== "number") { else { let y2: {} = strOrBool; // {} >y2 : {} ->strOrBool : nothing +>strOrBool : never } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfOther.types b/tests/baselines/reference/typeGuardOfFormTypeOfOther.types index c8c150b5a3b1f..8e42a8e0d8e26 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfOther.types +++ b/tests/baselines/reference/typeGuardOfFormTypeOfOther.types @@ -105,7 +105,7 @@ if (typeof strOrNumOrBool === "Object") { let q1: {} = strOrNumOrBool; // {} >q1 : {} ->strOrNumOrBool : nothing +>strOrNumOrBool : never } else { let q2: string | number | boolean = strOrNumOrBool; // string | number | boolean @@ -178,6 +178,6 @@ if (typeof strOrNumOrBool !== "Object") { else { let q2: {} = strOrNumOrBool; // {} >q2 : {} ->strOrNumOrBool : nothing +>strOrNumOrBool : never } diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfString.types b/tests/baselines/reference/typeGuardOfFormTypeOfString.types index 23c789fb98725..971109215f785 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfString.types +++ b/tests/baselines/reference/typeGuardOfFormTypeOfString.types @@ -121,7 +121,7 @@ if (typeof numOrBool === "string") { let x1: {} = numOrBool; // {} >x1 : {} ->numOrBool : nothing +>numOrBool : never } else { let x2: number | boolean = numOrBool; // number | boolean @@ -214,6 +214,6 @@ if (typeof numOrBool !== "string") { else { let x2: {} = numOrBool; // {} >x2 : {} ->numOrBool : nothing +>numOrBool : never } diff --git a/tests/baselines/reference/typeGuardsAsAssertions.types b/tests/baselines/reference/typeGuardsAsAssertions.types index 6ec84ada1f482..82e92a72d8d08 100644 --- a/tests/baselines/reference/typeGuardsAsAssertions.types +++ b/tests/baselines/reference/typeGuardsAsAssertions.types @@ -259,7 +259,7 @@ function f4() { >"boolean" : string x; // nothing (boolean not in declared type) ->x : nothing +>x : never } x; // undefined >x : undefined diff --git a/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt b/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt index 662d36971592f..dfcb8a598dae5 100644 --- a/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt +++ b/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts(7,20): error TS2339: Property 'global' does not exist on type 'nothing'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts(7,20): error TS2339: Property 'global' does not exist on type 'never'. ==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts (1 errors) ==== @@ -10,5 +10,5 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts(7,20) result = result2; } else if (!result.global) { ~~~~~~ -!!! error TS2339: Property 'global' does not exist on type 'nothing'. +!!! error TS2339: Property 'global' does not exist on type 'never'. } \ No newline at end of file diff --git a/tests/cases/conformance/types/never/neverType.ts b/tests/cases/conformance/types/never/neverType.ts new file mode 100644 index 0000000000000..d37528a022dd8 --- /dev/null +++ b/tests/cases/conformance/types/never/neverType.ts @@ -0,0 +1,68 @@ +// @strictNullChecks: true +// @declaration: true + +function error(message: string) { + throw new Error(message); +} + +function fail() { + return error("Something failed"); +} + +function infiniteLoop() { + while (true) { + } +} + +function move1(direction: "up" | "down") { + switch (direction) { + case "up": + return 1; + case "down": + return -1; + } + return error("Should never get here"); +} + +function move2(direction: "up" | "down") { + return direction === "up" ? 1 : + direction === "down" ? -1 : + error("Should never get here"); +} + +function check(x: T | undefined) { + return x || error("Undefined value"); +} + +function f1(x: string | number) { + if (typeof x === "boolean") { + x; // never + } +} + +function f2(x: string | number) { + while (true) { + if (typeof x === "boolean") { + return x; // never + } + } +} + +function failOrThrow(shouldFail: boolean) { + if (shouldFail) { + return fail(); + } + throw new Error(); +} + +function test(cb: () => string) { + let s = cb(); + return s; +} + +let errorCallback = () => error("Error callback"); + +test(() => "hello"); +test(() => fail()); +test(() => { throw new Error(); }) +test(errorCallback); diff --git a/tests/cases/conformance/types/never/neverTypeErrors1.ts b/tests/cases/conformance/types/never/neverTypeErrors1.ts new file mode 100644 index 0000000000000..8d78e863098c6 --- /dev/null +++ b/tests/cases/conformance/types/never/neverTypeErrors1.ts @@ -0,0 +1,20 @@ +function f1() { + let x: never; + x = 1; + x = "abc"; + x = false; + x = undefined; + x = null; + x = {}; +} + +function f2(): never { + return; +} + +function f3(): never { + return 1; +} + +function f4(): never { +} \ No newline at end of file diff --git a/tests/cases/conformance/types/never/neverTypeErrors2.ts b/tests/cases/conformance/types/never/neverTypeErrors2.ts new file mode 100644 index 0000000000000..635d1c9c6ad79 --- /dev/null +++ b/tests/cases/conformance/types/never/neverTypeErrors2.ts @@ -0,0 +1,22 @@ +// @strictNullChecks: true + +function f1() { + let x: never; + x = 1; + x = "abc"; + x = false; + x = undefined; + x = null; + x = {}; +} + +function f2(): never { + return; +} + +function f3(): never { + return 1; +} + +function f4(): never { +} \ No newline at end of file