diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6a720d947d..95e33be8eb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -122,7 +122,7 @@ namespace ts { const unknownType = createIntrinsicType(TypeFlags.Any, "unknown"); const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - const nothingType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + const neverType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); const emptyGenericType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); emptyGenericType.instantiations = {}; @@ -2029,8 +2029,8 @@ namespace ts { writeUnionOrIntersectionType(type, flags); } else if (type.flags & TypeFlags.Anonymous) { - if (type === nothingType) { - writer.writeKeyword("nothing"); + if (type === neverType) { + writer.writeKeyword("never"); } else { writeAnonymousType(type, flags); @@ -3670,6 +3670,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 +5006,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 +5047,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 +5067,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 +5215,8 @@ namespace ts { return undefinedType; case SyntaxKind.NullKeyword: return nullType; + case SyntaxKind.NeverKeyword: + return neverType; case SyntaxKind.ThisType: case SyntaxKind.ThisKeyword: return getTypeFromThisTypeNode(node); @@ -7485,7 +7488,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 +7505,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 +7625,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 +7713,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 +7723,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 +7945,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 { @@ -11559,7 +11562,7 @@ namespace ts { return promiseType; } else { - return voidType; + return hasImplicitReturn ? voidType : neverType; } } } @@ -14747,7 +14750,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 +14762,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; } } diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index c24135ba52..9e4f789674 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/parser.ts b/src/compiler/parser.ts index daebf8a930..b60082969d 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 8979814a7a..1a2748b38b 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 777141b45f..fbe1f3c60c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -164,6 +164,7 @@ namespace ts { IsKeyword, ModuleKeyword, NamespaceKeyword, + NeverKeyword, ReadonlyKeyword, RequireKeyword, NumberKeyword, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 42ba6b9d0f..9a86e223eb 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;