Merge pull request #8652 from Microsoft/neverType

Add 'never' type
This commit is contained in:
Anders Hejlsberg 2016-05-18 11:39:22 -07:00
commit 59f269c90a
37 changed files with 861 additions and 90 deletions

View File

@ -121,9 +121,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 = <GenericType><ObjectType>createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
emptyGenericType.instantiations = {};
@ -2030,12 +2030,7 @@ namespace ts {
writeUnionOrIntersectionType(<UnionOrIntersectionType>type, flags);
}
else if (type.flags & TypeFlags.Anonymous) {
if (type === nothingType) {
writer.writeKeyword("nothing");
}
else {
writeAnonymousType(<ObjectType>type, flags);
}
writeAnonymousType(<ObjectType>type, flags);
}
else if (type.flags & TypeFlags.StringLiteral) {
writer.writeStringLiteral(`"${escapeString((<StringLiteralType>type).text)}"`);
@ -3676,6 +3671,7 @@ namespace ts {
case SyntaxKind.VoidKeyword:
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NullKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.StringLiteralType:
return true;
case SyntaxKind.ArrayType:
@ -5011,7 +5007,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);
}
}
@ -5052,7 +5048,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];
@ -5072,7 +5068,7 @@ namespace ts {
if (typeSet.length === 0) {
return typeSet.containsNull ? nullType :
typeSet.containsUndefined ? undefinedType :
nothingType;
neverType;
}
else if (typeSet.length === 1) {
return typeSet[0];
@ -5220,6 +5216,8 @@ namespace ts {
return undefinedType;
case SyntaxKind.NullKeyword:
return nullType;
case SyntaxKind.NeverKeyword:
return neverType;
case SyntaxKind.ThisType:
case SyntaxKind.ThisKeyword:
return getTypeFromThisTypeNode(node);
@ -5865,28 +5863,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) {
@ -7491,7 +7489,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[];
@ -7508,7 +7506,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) {
@ -7629,7 +7627,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;
@ -7717,7 +7715,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
@ -7727,7 +7725,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);
}
}
@ -7949,7 +7947,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 {
@ -11561,6 +11559,9 @@ namespace ts {
else {
const hasImplicitReturn = !!(func.flags & NodeFlags.HasImplicitReturn);
types = checkAndAggregateReturnExpressionTypes(<Block>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.
@ -11569,12 +11570,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.
@ -11654,7 +11652,7 @@ namespace ts {
// the native Promise<T> 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);
}
}
@ -11662,6 +11660,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);
@ -11697,7 +11698,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
@ -14761,7 +14765,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;
@ -14773,7 +14777,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;
}
}
@ -14834,7 +14838,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) {

View File

@ -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);

View File

@ -1747,6 +1747,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

View File

@ -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:

View File

@ -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,

View File

@ -164,6 +164,7 @@ namespace ts {
IsKeyword,
ModuleKeyword,
NamespaceKeyword,
NeverKeyword,
ReadonlyKeyword,
RequireKeyword,
NumberKeyword,
@ -2171,11 +2172,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,

View File

@ -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;

View File

@ -4,7 +4,7 @@ let cond: boolean;
>cond : boolean
function ff() {
>ff : () => void
>ff : () => never
let x: string | undefined;
>x : string | undefined

View File

@ -7,7 +7,7 @@ while (true) {
>true : boolean
function f() {
>f : () => void
>f : () => never
target:
>target : any

View File

@ -16,7 +16,7 @@ for (var x = <number>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

View File

@ -133,8 +133,8 @@ function fn5(x: Derived1) {
// 1.5: y: Derived1
// Want: ???
let y = x;
>y : nothing
>x : nothing
>y : never
>x : never
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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<T>(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<T>(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;

View File

@ -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<T>(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))

View File

@ -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<T>(x: T | undefined) {
>check : <T>(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

View File

@ -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.
}

View File

@ -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() {
}

View File

@ -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.
}

View File

@ -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() {
}

View File

@ -7,7 +7,7 @@ while (true) {
>true : boolean
function f() {
>f : () => void
>f : () => never
target:
>target : any

View File

@ -63,7 +63,7 @@ var x3 = f1()
.then(f2, (e: Error) => {
>then : { <TResult>(onfulfilled?: (value: T1) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => TResult | PromiseLike<TResult>): Promise<TResult>; <TResult>(onfulfilled?: (value: T1) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): Promise<TResult>; }
>f2 : (x: T1) => T2
>(e: Error) => { throw e;} : (e: Error) => void
>(e: Error) => { throw e;} : (e: Error) => never
>e : Error
>Error : Error

View File

@ -116,6 +116,6 @@ if (!hasKind(x, "B")) {
}
else {
let d = x;
>d : nothing
>x : nothing
>d : never
>x : never
}

View File

@ -110,6 +110,6 @@ if (!hasKind(x, "B")) {
}
else {
let d = x;
>d : nothing
>x : nothing
>d : never
>x : never
}

View File

@ -113,6 +113,6 @@ if (!hasKind(x, "B")) {
}
else {
let d = x;
>d : nothing
>x : nothing
>d : never
>x : never
}

View File

@ -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) {
}
<T>(x: T) => { throw x; }
><T>(x: T) => { throw x; } : <T>(x: T) => void
><T>(x: T) => { throw x; } : <T>(x: T) => never
>T : T
>x : T
>T : T
@ -78,7 +78,7 @@ class C<T> {
>T : T
biz() {
>biz : () => void
>biz : () => never
throw this.value;
>this.value : T
@ -93,15 +93,15 @@ class C<T> {
}
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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -259,7 +259,7 @@ function f4() {
>"boolean" : string
x; // nothing (boolean not in declared type)
>x : nothing
>x : never
}
x; // undefined
>x : undefined

View File

@ -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'.
}

View File

@ -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<T>(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);

View File

@ -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 {
}

View File

@ -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 {
}