mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 11:35:42 -06:00
Merge pull request #5442 from weswigham/empty-set
Improve type guard consistiency
This commit is contained in:
commit
b3f0a71082
@ -109,9 +109,9 @@ namespace ts {
|
||||
const undefinedType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsUndefinedOrNull, "undefined");
|
||||
const nullType = createIntrinsicType(TypeFlags.Null | TypeFlags.ContainsUndefinedOrNull, "null");
|
||||
const unknownType = createIntrinsicType(TypeFlags.Any, "unknown");
|
||||
const circularType = createIntrinsicType(TypeFlags.Any, "__circular__");
|
||||
|
||||
const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
||||
const emptyUnionType = emptyObjectType;
|
||||
const emptyGenericType = <GenericType><ObjectType>createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
||||
emptyGenericType.instantiations = {};
|
||||
|
||||
@ -4413,7 +4413,7 @@ namespace ts {
|
||||
// a named type that circularly references itself.
|
||||
function getUnionType(types: Type[], noSubtypeReduction?: boolean): Type {
|
||||
if (types.length === 0) {
|
||||
return emptyObjectType;
|
||||
return emptyUnionType;
|
||||
}
|
||||
const typeSet: Type[] = [];
|
||||
addTypesToSet(typeSet, types, TypeFlags.Union);
|
||||
@ -6285,27 +6285,6 @@ namespace ts {
|
||||
Debug.fail("should not get here");
|
||||
}
|
||||
|
||||
// For a union type, remove all constituent types that are of the given type kind (when isOfTypeKind is true)
|
||||
// or not of the given type kind (when isOfTypeKind is false)
|
||||
function removeTypesFromUnionType(type: Type, typeKind: TypeFlags, isOfTypeKind: boolean, allowEmptyUnionResult: boolean): Type {
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
const types = (<UnionType>type).types;
|
||||
if (forEach(types, t => !!(t.flags & typeKind) === isOfTypeKind)) {
|
||||
// Above we checked if we have anything to remove, now use the opposite test to do the removal
|
||||
const narrowedType = getUnionType(filter(types, t => !(t.flags & typeKind) === isOfTypeKind));
|
||||
if (allowEmptyUnionResult || narrowedType !== emptyObjectType) {
|
||||
return narrowedType;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (allowEmptyUnionResult && !!(type.flags & typeKind) === isOfTypeKind) {
|
||||
// Use getUnionType(emptyArray) instead of emptyObjectType in case the way empty union types
|
||||
// are represented ever changes.
|
||||
return getUnionType(emptyArray);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function hasInitializer(node: VariableLikeDeclaration): boolean {
|
||||
return !!(node.initializer || isBindingPattern(node.parent) && hasInitializer(<VariableLikeDeclaration>node.parent.parent));
|
||||
}
|
||||
@ -6407,33 +6386,16 @@ namespace ts {
|
||||
// Only narrow when symbol is variable of type any or an object, union, or type parameter type
|
||||
if (node && symbol.flags & SymbolFlags.Variable) {
|
||||
if (isTypeAny(type) || type.flags & (TypeFlags.ObjectType | TypeFlags.Union | TypeFlags.TypeParameter)) {
|
||||
const originalType = type;
|
||||
const nodeStack: {node: Node, child: Node}[] = [];
|
||||
loop: while (node.parent) {
|
||||
const child = node;
|
||||
node = node.parent;
|
||||
let narrowedType = type;
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.IfStatement:
|
||||
// In a branch of an if statement, narrow based on controlling expression
|
||||
if (child !== (<IfStatement>node).expression) {
|
||||
narrowedType = narrowType(type, (<IfStatement>node).expression, /*assumeTrue*/ child === (<IfStatement>node).thenStatement);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
// In a branch of a conditional expression, narrow based on controlling condition
|
||||
if (child !== (<ConditionalExpression>node).condition) {
|
||||
narrowedType = narrowType(type, (<ConditionalExpression>node).condition, /*assumeTrue*/ child === (<ConditionalExpression>node).whenTrue);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.BinaryExpression:
|
||||
// In the right operand of an && or ||, narrow based on left operand
|
||||
if (child === (<BinaryExpression>node).right) {
|
||||
if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
|
||||
narrowedType = narrowType(type, (<BinaryExpression>node).left, /*assumeTrue*/ true);
|
||||
}
|
||||
else if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken) {
|
||||
narrowedType = narrowType(type, (<BinaryExpression>node).left, /*assumeTrue*/ false);
|
||||
}
|
||||
}
|
||||
nodeStack.push({node, child});
|
||||
break;
|
||||
case SyntaxKind.SourceFile:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
@ -6446,13 +6408,48 @@ namespace ts {
|
||||
// Stop at the first containing function or module declaration
|
||||
break loop;
|
||||
}
|
||||
// Use narrowed type if construct contains no assignments to variable
|
||||
if (narrowedType !== type) {
|
||||
if (isVariableAssignedWithin(symbol, node)) {
|
||||
}
|
||||
|
||||
let nodes: {node: Node, child: Node};
|
||||
while (nodes = nodeStack.pop()) {
|
||||
const {node, child} = nodes;
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.IfStatement:
|
||||
// In a branch of an if statement, narrow based on controlling expression
|
||||
if (child !== (<IfStatement>node).expression) {
|
||||
type = narrowType(type, (<IfStatement>node).expression, /*assumeTrue*/ child === (<IfStatement>node).thenStatement);
|
||||
}
|
||||
break;
|
||||
}
|
||||
type = narrowedType;
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
// In a branch of a conditional expression, narrow based on controlling condition
|
||||
if (child !== (<ConditionalExpression>node).condition) {
|
||||
type = narrowType(type, (<ConditionalExpression>node).condition, /*assumeTrue*/ child === (<ConditionalExpression>node).whenTrue);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.BinaryExpression:
|
||||
// In the right operand of an && or ||, narrow based on left operand
|
||||
if (child === (<BinaryExpression>node).right) {
|
||||
if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
|
||||
type = narrowType(type, (<BinaryExpression>node).left, /*assumeTrue*/ true);
|
||||
}
|
||||
else if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken) {
|
||||
type = narrowType(type, (<BinaryExpression>node).left, /*assumeTrue*/ false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Debug.fail("Unreachable!");
|
||||
}
|
||||
|
||||
// Use original type if construct contains assignments to variable
|
||||
if (type !== originalType && isVariableAssignedWithin(symbol, node)) {
|
||||
type = originalType;
|
||||
}
|
||||
}
|
||||
|
||||
// Preserve old top-level behavior - if the branch is really an empty set, revert to prior type
|
||||
if (type === emptyUnionType) {
|
||||
type = originalType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6469,31 +6466,31 @@ namespace ts {
|
||||
if (left.expression.kind !== SyntaxKind.Identifier || getResolvedSymbol(<Identifier>left.expression) !== symbol) {
|
||||
return type;
|
||||
}
|
||||
const typeInfo = primitiveTypeInfo[right.text];
|
||||
if (expr.operatorToken.kind === SyntaxKind.ExclamationEqualsEqualsToken) {
|
||||
assumeTrue = !assumeTrue;
|
||||
}
|
||||
if (assumeTrue) {
|
||||
// Assumed result is true. If check was not for a primitive type, remove all primitive types
|
||||
if (!typeInfo) {
|
||||
return removeTypesFromUnionType(type, /*typeKind*/ TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.Boolean | TypeFlags.ESSymbol,
|
||||
/*isOfTypeKind*/ true, /*allowEmptyUnionResult*/ false);
|
||||
}
|
||||
// Check was for a primitive type, return that primitive type if it is a subtype
|
||||
if (isTypeSubtypeOf(typeInfo.type, type)) {
|
||||
return typeInfo.type;
|
||||
}
|
||||
// Otherwise, remove all types that aren't of the primitive type kind. This can happen when the type is
|
||||
// union of enum types and other types.
|
||||
return removeTypesFromUnionType(type, /*typeKind*/ typeInfo.flags, /*isOfTypeKind*/ false, /*allowEmptyUnionResult*/ false);
|
||||
const typeInfo = primitiveTypeInfo[right.text];
|
||||
// If the type to be narrowed is any and we're checking a primitive with assumeTrue=true, return the primitive
|
||||
if (!!(type.flags & TypeFlags.Any) && typeInfo && assumeTrue) {
|
||||
return typeInfo.type;
|
||||
}
|
||||
let flags: TypeFlags;
|
||||
if (typeInfo) {
|
||||
flags = typeInfo.flags;
|
||||
}
|
||||
else {
|
||||
// Assumed result is false. If check was for a primitive type, remove that primitive type
|
||||
if (typeInfo) {
|
||||
return removeTypesFromUnionType(type, /*typeKind*/ typeInfo.flags, /*isOfTypeKind*/ true, /*allowEmptyUnionResult*/ false);
|
||||
}
|
||||
// Otherwise we don't have enough information to do anything.
|
||||
return type;
|
||||
assumeTrue = !assumeTrue;
|
||||
flags = TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.ESSymbol | TypeFlags.Boolean;
|
||||
}
|
||||
// At this point we can bail if it's not a union
|
||||
if (!(type.flags & TypeFlags.Union)) {
|
||||
// If the active non-union type would be removed from a union by this type guard, return an empty union
|
||||
return filterUnion(type) ? type : emptyUnionType;
|
||||
}
|
||||
return getUnionType(filter((type as UnionType).types, filterUnion), /*noSubtypeReduction*/ true);
|
||||
|
||||
function filterUnion(type: Type) {
|
||||
return assumeTrue === !!(type.flags & flags);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6507,7 +6504,7 @@ namespace ts {
|
||||
// and the second operand was false. We narrow with those assumptions and union the two resulting types.
|
||||
return getUnionType([
|
||||
narrowType(type, expr.left, /*assumeTrue*/ false),
|
||||
narrowType(narrowType(type, expr.left, /*assumeTrue*/ true), expr.right, /*assumeTrue*/ false)
|
||||
narrowType(type, expr.right, /*assumeTrue*/ false)
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -6518,7 +6515,7 @@ namespace ts {
|
||||
// and the second operand was true. We narrow with those assumptions and union the two resulting types.
|
||||
return getUnionType([
|
||||
narrowType(type, expr.left, /*assumeTrue*/ true),
|
||||
narrowType(narrowType(type, expr.left, /*assumeTrue*/ false), expr.right, /*assumeTrue*/ true)
|
||||
narrowType(type, expr.right, /*assumeTrue*/ true)
|
||||
]);
|
||||
}
|
||||
else {
|
||||
@ -12736,9 +12733,14 @@ namespace ts {
|
||||
|
||||
// After we remove all types that are StringLike, we will know if there was a string constituent
|
||||
// based on whether the remaining type is the same as the initial type.
|
||||
const arrayType = removeTypesFromUnionType(arrayOrStringType, TypeFlags.StringLike, /*isTypeOfKind*/ true, /*allowEmptyUnionResult*/ true);
|
||||
let arrayType = arrayOrStringType;
|
||||
if (arrayOrStringType.flags & TypeFlags.Union) {
|
||||
arrayType = getUnionType(filter((arrayOrStringType as UnionType).types, t => !(t.flags & TypeFlags.StringLike)));
|
||||
}
|
||||
else if (arrayOrStringType.flags & TypeFlags.StringLike) {
|
||||
arrayType = emptyUnionType;
|
||||
}
|
||||
const hasStringConstituent = arrayOrStringType !== arrayType;
|
||||
|
||||
let reportedError = false;
|
||||
if (hasStringConstituent) {
|
||||
if (languageVersion < ScriptTarget.ES5) {
|
||||
|
||||
@ -21,5 +21,5 @@ if (typeof x === "object") {
|
||||
}
|
||||
else {
|
||||
x;
|
||||
>x : symbol | Foo
|
||||
>x : symbol
|
||||
}
|
||||
|
||||
41
tests/baselines/reference/typeGuardEnums.js
Normal file
41
tests/baselines/reference/typeGuardEnums.js
Normal file
@ -0,0 +1,41 @@
|
||||
//// [typeGuardEnums.ts]
|
||||
enum E {}
|
||||
enum V {}
|
||||
|
||||
let x: number|string|E|V;
|
||||
|
||||
if (typeof x === "number") {
|
||||
x; // number|E|V
|
||||
}
|
||||
else {
|
||||
x; // string
|
||||
}
|
||||
|
||||
if (typeof x !== "number") {
|
||||
x; // string
|
||||
}
|
||||
else {
|
||||
x; // number|E|V
|
||||
}
|
||||
|
||||
|
||||
//// [typeGuardEnums.js]
|
||||
var E;
|
||||
(function (E) {
|
||||
})(E || (E = {}));
|
||||
var V;
|
||||
(function (V) {
|
||||
})(V || (V = {}));
|
||||
var x;
|
||||
if (typeof x === "number") {
|
||||
x; // number|E|V
|
||||
}
|
||||
else {
|
||||
x; // string
|
||||
}
|
||||
if (typeof x !== "number") {
|
||||
x; // string
|
||||
}
|
||||
else {
|
||||
x; // number|E|V
|
||||
}
|
||||
34
tests/baselines/reference/typeGuardEnums.symbols
Normal file
34
tests/baselines/reference/typeGuardEnums.symbols
Normal file
@ -0,0 +1,34 @@
|
||||
=== tests/cases/conformance/expressions/typeGuards/typeGuardEnums.ts ===
|
||||
enum E {}
|
||||
>E : Symbol(E, Decl(typeGuardEnums.ts, 0, 0))
|
||||
|
||||
enum V {}
|
||||
>V : Symbol(V, Decl(typeGuardEnums.ts, 0, 9))
|
||||
|
||||
let x: number|string|E|V;
|
||||
>x : Symbol(x, Decl(typeGuardEnums.ts, 3, 3))
|
||||
>E : Symbol(E, Decl(typeGuardEnums.ts, 0, 0))
|
||||
>V : Symbol(V, Decl(typeGuardEnums.ts, 0, 9))
|
||||
|
||||
if (typeof x === "number") {
|
||||
>x : Symbol(x, Decl(typeGuardEnums.ts, 3, 3))
|
||||
|
||||
x; // number|E|V
|
||||
>x : Symbol(x, Decl(typeGuardEnums.ts, 3, 3))
|
||||
}
|
||||
else {
|
||||
x; // string
|
||||
>x : Symbol(x, Decl(typeGuardEnums.ts, 3, 3))
|
||||
}
|
||||
|
||||
if (typeof x !== "number") {
|
||||
>x : Symbol(x, Decl(typeGuardEnums.ts, 3, 3))
|
||||
|
||||
x; // string
|
||||
>x : Symbol(x, Decl(typeGuardEnums.ts, 3, 3))
|
||||
}
|
||||
else {
|
||||
x; // number|E|V
|
||||
>x : Symbol(x, Decl(typeGuardEnums.ts, 3, 3))
|
||||
}
|
||||
|
||||
40
tests/baselines/reference/typeGuardEnums.types
Normal file
40
tests/baselines/reference/typeGuardEnums.types
Normal file
@ -0,0 +1,40 @@
|
||||
=== tests/cases/conformance/expressions/typeGuards/typeGuardEnums.ts ===
|
||||
enum E {}
|
||||
>E : E
|
||||
|
||||
enum V {}
|
||||
>V : V
|
||||
|
||||
let x: number|string|E|V;
|
||||
>x : number | string | E | V
|
||||
>E : E
|
||||
>V : V
|
||||
|
||||
if (typeof x === "number") {
|
||||
>typeof x === "number" : boolean
|
||||
>typeof x : string
|
||||
>x : number | string | E | V
|
||||
>"number" : string
|
||||
|
||||
x; // number|E|V
|
||||
>x : number | E | V
|
||||
}
|
||||
else {
|
||||
x; // string
|
||||
>x : string
|
||||
}
|
||||
|
||||
if (typeof x !== "number") {
|
||||
>typeof x !== "number" : boolean
|
||||
>typeof x : string
|
||||
>x : number | string | E | V
|
||||
>"number" : string
|
||||
|
||||
x; // string
|
||||
>x : string
|
||||
}
|
||||
else {
|
||||
x; // number|E|V
|
||||
>x : number | E | V
|
||||
}
|
||||
|
||||
31
tests/baselines/reference/typeGuardNesting.js
Normal file
31
tests/baselines/reference/typeGuardNesting.js
Normal file
@ -0,0 +1,31 @@
|
||||
//// [typeGuardNesting.ts]
|
||||
let strOrBool: string|boolean;
|
||||
if ((typeof strOrBool === 'boolean' && !strOrBool) || typeof strOrBool === 'string') {
|
||||
let label: string = (typeof strOrBool === 'string') ? strOrBool : "string";
|
||||
let bool: boolean = (typeof strOrBool === 'boolean') ? strOrBool : false;
|
||||
let label2: string = (typeof strOrBool !== 'boolean') ? strOrBool : "string";
|
||||
let bool2: boolean = (typeof strOrBool !== 'string') ? strOrBool : false;
|
||||
}
|
||||
|
||||
if ((typeof strOrBool !== 'string' && !strOrBool) || typeof strOrBool !== 'boolean') {
|
||||
let label: string = (typeof strOrBool === 'string') ? strOrBool : "string";
|
||||
let bool: boolean = (typeof strOrBool === 'boolean') ? strOrBool : false;
|
||||
let label2: string = (typeof strOrBool !== 'boolean') ? strOrBool : "string";
|
||||
let bool2: boolean = (typeof strOrBool !== 'string') ? strOrBool : false;
|
||||
}
|
||||
|
||||
|
||||
//// [typeGuardNesting.js]
|
||||
var strOrBool;
|
||||
if ((typeof strOrBool === 'boolean' && !strOrBool) || typeof strOrBool === 'string') {
|
||||
var label = (typeof strOrBool === 'string') ? strOrBool : "string";
|
||||
var bool = (typeof strOrBool === 'boolean') ? strOrBool : false;
|
||||
var label2 = (typeof strOrBool !== 'boolean') ? strOrBool : "string";
|
||||
var bool2 = (typeof strOrBool !== 'string') ? strOrBool : false;
|
||||
}
|
||||
if ((typeof strOrBool !== 'string' && !strOrBool) || typeof strOrBool !== 'boolean') {
|
||||
var label = (typeof strOrBool === 'string') ? strOrBool : "string";
|
||||
var bool = (typeof strOrBool === 'boolean') ? strOrBool : false;
|
||||
var label2 = (typeof strOrBool !== 'boolean') ? strOrBool : "string";
|
||||
var bool2 = (typeof strOrBool !== 'string') ? strOrBool : false;
|
||||
}
|
||||
56
tests/baselines/reference/typeGuardNesting.symbols
Normal file
56
tests/baselines/reference/typeGuardNesting.symbols
Normal file
@ -0,0 +1,56 @@
|
||||
=== tests/cases/conformance/expressions/typeGuards/typeGuardNesting.ts ===
|
||||
let strOrBool: string|boolean;
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
|
||||
if ((typeof strOrBool === 'boolean' && !strOrBool) || typeof strOrBool === 'string') {
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
|
||||
let label: string = (typeof strOrBool === 'string') ? strOrBool : "string";
|
||||
>label : Symbol(label, Decl(typeGuardNesting.ts, 2, 4))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
|
||||
let bool: boolean = (typeof strOrBool === 'boolean') ? strOrBool : false;
|
||||
>bool : Symbol(bool, Decl(typeGuardNesting.ts, 3, 4))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
|
||||
let label2: string = (typeof strOrBool !== 'boolean') ? strOrBool : "string";
|
||||
>label2 : Symbol(label2, Decl(typeGuardNesting.ts, 4, 4))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
|
||||
let bool2: boolean = (typeof strOrBool !== 'string') ? strOrBool : false;
|
||||
>bool2 : Symbol(bool2, Decl(typeGuardNesting.ts, 5, 4))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
}
|
||||
|
||||
if ((typeof strOrBool !== 'string' && !strOrBool) || typeof strOrBool !== 'boolean') {
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
|
||||
let label: string = (typeof strOrBool === 'string') ? strOrBool : "string";
|
||||
>label : Symbol(label, Decl(typeGuardNesting.ts, 9, 4))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
|
||||
let bool: boolean = (typeof strOrBool === 'boolean') ? strOrBool : false;
|
||||
>bool : Symbol(bool, Decl(typeGuardNesting.ts, 10, 4))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
|
||||
let label2: string = (typeof strOrBool !== 'boolean') ? strOrBool : "string";
|
||||
>label2 : Symbol(label2, Decl(typeGuardNesting.ts, 11, 4))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
|
||||
let bool2: boolean = (typeof strOrBool !== 'string') ? strOrBool : false;
|
||||
>bool2 : Symbol(bool2, Decl(typeGuardNesting.ts, 12, 4))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
>strOrBool : Symbol(strOrBool, Decl(typeGuardNesting.ts, 0, 3))
|
||||
}
|
||||
|
||||
124
tests/baselines/reference/typeGuardNesting.types
Normal file
124
tests/baselines/reference/typeGuardNesting.types
Normal file
@ -0,0 +1,124 @@
|
||||
=== tests/cases/conformance/expressions/typeGuards/typeGuardNesting.ts ===
|
||||
let strOrBool: string|boolean;
|
||||
>strOrBool : string | boolean
|
||||
|
||||
if ((typeof strOrBool === 'boolean' && !strOrBool) || typeof strOrBool === 'string') {
|
||||
>(typeof strOrBool === 'boolean' && !strOrBool) || typeof strOrBool === 'string' : boolean
|
||||
>(typeof strOrBool === 'boolean' && !strOrBool) : boolean
|
||||
>typeof strOrBool === 'boolean' && !strOrBool : boolean
|
||||
>typeof strOrBool === 'boolean' : boolean
|
||||
>typeof strOrBool : string
|
||||
>strOrBool : string | boolean
|
||||
>'boolean' : string
|
||||
>!strOrBool : boolean
|
||||
>strOrBool : boolean
|
||||
>typeof strOrBool === 'string' : boolean
|
||||
>typeof strOrBool : string
|
||||
>strOrBool : string | boolean
|
||||
>'string' : string
|
||||
|
||||
let label: string = (typeof strOrBool === 'string') ? strOrBool : "string";
|
||||
>label : string
|
||||
>(typeof strOrBool === 'string') ? strOrBool : "string" : string
|
||||
>(typeof strOrBool === 'string') : boolean
|
||||
>typeof strOrBool === 'string' : boolean
|
||||
>typeof strOrBool : string
|
||||
>strOrBool : boolean | string
|
||||
>'string' : string
|
||||
>strOrBool : string
|
||||
>"string" : string
|
||||
|
||||
let bool: boolean = (typeof strOrBool === 'boolean') ? strOrBool : false;
|
||||
>bool : boolean
|
||||
>(typeof strOrBool === 'boolean') ? strOrBool : false : boolean
|
||||
>(typeof strOrBool === 'boolean') : boolean
|
||||
>typeof strOrBool === 'boolean' : boolean
|
||||
>typeof strOrBool : string
|
||||
>strOrBool : boolean | string
|
||||
>'boolean' : string
|
||||
>strOrBool : boolean
|
||||
>false : boolean
|
||||
|
||||
let label2: string = (typeof strOrBool !== 'boolean') ? strOrBool : "string";
|
||||
>label2 : string
|
||||
>(typeof strOrBool !== 'boolean') ? strOrBool : "string" : string
|
||||
>(typeof strOrBool !== 'boolean') : boolean
|
||||
>typeof strOrBool !== 'boolean' : boolean
|
||||
>typeof strOrBool : string
|
||||
>strOrBool : boolean | string
|
||||
>'boolean' : string
|
||||
>strOrBool : string
|
||||
>"string" : string
|
||||
|
||||
let bool2: boolean = (typeof strOrBool !== 'string') ? strOrBool : false;
|
||||
>bool2 : boolean
|
||||
>(typeof strOrBool !== 'string') ? strOrBool : false : boolean
|
||||
>(typeof strOrBool !== 'string') : boolean
|
||||
>typeof strOrBool !== 'string' : boolean
|
||||
>typeof strOrBool : string
|
||||
>strOrBool : boolean | string
|
||||
>'string' : string
|
||||
>strOrBool : boolean
|
||||
>false : boolean
|
||||
}
|
||||
|
||||
if ((typeof strOrBool !== 'string' && !strOrBool) || typeof strOrBool !== 'boolean') {
|
||||
>(typeof strOrBool !== 'string' && !strOrBool) || typeof strOrBool !== 'boolean' : boolean
|
||||
>(typeof strOrBool !== 'string' && !strOrBool) : boolean
|
||||
>typeof strOrBool !== 'string' && !strOrBool : boolean
|
||||
>typeof strOrBool !== 'string' : boolean
|
||||
>typeof strOrBool : string
|
||||
>strOrBool : string | boolean
|
||||
>'string' : string
|
||||
>!strOrBool : boolean
|
||||
>strOrBool : boolean
|
||||
>typeof strOrBool !== 'boolean' : boolean
|
||||
>typeof strOrBool : string
|
||||
>strOrBool : string | boolean
|
||||
>'boolean' : string
|
||||
|
||||
let label: string = (typeof strOrBool === 'string') ? strOrBool : "string";
|
||||
>label : string
|
||||
>(typeof strOrBool === 'string') ? strOrBool : "string" : string
|
||||
>(typeof strOrBool === 'string') : boolean
|
||||
>typeof strOrBool === 'string' : boolean
|
||||
>typeof strOrBool : string
|
||||
>strOrBool : boolean | string
|
||||
>'string' : string
|
||||
>strOrBool : string
|
||||
>"string" : string
|
||||
|
||||
let bool: boolean = (typeof strOrBool === 'boolean') ? strOrBool : false;
|
||||
>bool : boolean
|
||||
>(typeof strOrBool === 'boolean') ? strOrBool : false : boolean
|
||||
>(typeof strOrBool === 'boolean') : boolean
|
||||
>typeof strOrBool === 'boolean' : boolean
|
||||
>typeof strOrBool : string
|
||||
>strOrBool : boolean | string
|
||||
>'boolean' : string
|
||||
>strOrBool : boolean
|
||||
>false : boolean
|
||||
|
||||
let label2: string = (typeof strOrBool !== 'boolean') ? strOrBool : "string";
|
||||
>label2 : string
|
||||
>(typeof strOrBool !== 'boolean') ? strOrBool : "string" : string
|
||||
>(typeof strOrBool !== 'boolean') : boolean
|
||||
>typeof strOrBool !== 'boolean' : boolean
|
||||
>typeof strOrBool : string
|
||||
>strOrBool : boolean | string
|
||||
>'boolean' : string
|
||||
>strOrBool : string
|
||||
>"string" : string
|
||||
|
||||
let bool2: boolean = (typeof strOrBool !== 'string') ? strOrBool : false;
|
||||
>bool2 : boolean
|
||||
>(typeof strOrBool !== 'string') ? strOrBool : false : boolean
|
||||
>(typeof strOrBool !== 'string') : boolean
|
||||
>typeof strOrBool !== 'string' : boolean
|
||||
>typeof strOrBool : string
|
||||
>strOrBool : boolean | string
|
||||
>'string' : string
|
||||
>strOrBool : boolean
|
||||
>false : boolean
|
||||
}
|
||||
|
||||
@ -23,19 +23,19 @@ if (typeof strOrC === "Object") {
|
||||
c = strOrC; // C
|
||||
}
|
||||
else {
|
||||
var r2: string | C = strOrC; // string | C
|
||||
var r2: string = strOrC; // string
|
||||
}
|
||||
if (typeof numOrC === "Object") {
|
||||
c = numOrC; // C
|
||||
}
|
||||
else {
|
||||
var r3: number | C = numOrC; // number | C
|
||||
var r3: number = numOrC; // number
|
||||
}
|
||||
if (typeof boolOrC === "Object") {
|
||||
c = boolOrC; // C
|
||||
}
|
||||
else {
|
||||
var r4: boolean | C = boolOrC; // boolean | C
|
||||
var r4: boolean = boolOrC; // boolean
|
||||
}
|
||||
|
||||
// Narrowing occurs only if target type is a subtype of variable type
|
||||
@ -50,19 +50,19 @@ else {
|
||||
// - when true, narrows the type of x by typeof x === s when false, or
|
||||
// - when false, narrows the type of x by typeof x === s when true.
|
||||
if (typeof strOrC !== "Object") {
|
||||
var r2: string | C = strOrC; // string | C
|
||||
var r2: string = strOrC; // string
|
||||
}
|
||||
else {
|
||||
c = strOrC; // C
|
||||
}
|
||||
if (typeof numOrC !== "Object") {
|
||||
var r3: number | C = numOrC; // number | C
|
||||
var r3: number = numOrC; // number
|
||||
}
|
||||
else {
|
||||
c = numOrC; // C
|
||||
}
|
||||
if (typeof boolOrC !== "Object") {
|
||||
var r4: boolean | C = boolOrC; // boolean | C
|
||||
var r4: boolean = boolOrC; // boolean
|
||||
}
|
||||
else {
|
||||
c = boolOrC; // C
|
||||
@ -104,19 +104,19 @@ if (typeof strOrC === "Object") {
|
||||
c = strOrC; // C
|
||||
}
|
||||
else {
|
||||
var r2 = strOrC; // string | C
|
||||
var r2 = strOrC; // string
|
||||
}
|
||||
if (typeof numOrC === "Object") {
|
||||
c = numOrC; // C
|
||||
}
|
||||
else {
|
||||
var r3 = numOrC; // number | C
|
||||
var r3 = numOrC; // number
|
||||
}
|
||||
if (typeof boolOrC === "Object") {
|
||||
c = boolOrC; // C
|
||||
}
|
||||
else {
|
||||
var r4 = boolOrC; // boolean | C
|
||||
var r4 = boolOrC; // boolean
|
||||
}
|
||||
// Narrowing occurs only if target type is a subtype of variable type
|
||||
if (typeof strOrNumOrBool === "Object") {
|
||||
@ -129,19 +129,19 @@ else {
|
||||
// - when true, narrows the type of x by typeof x === s when false, or
|
||||
// - when false, narrows the type of x by typeof x === s when true.
|
||||
if (typeof strOrC !== "Object") {
|
||||
var r2 = strOrC; // string | C
|
||||
var r2 = strOrC; // string
|
||||
}
|
||||
else {
|
||||
c = strOrC; // C
|
||||
}
|
||||
if (typeof numOrC !== "Object") {
|
||||
var r3 = numOrC; // number | C
|
||||
var r3 = numOrC; // number
|
||||
}
|
||||
else {
|
||||
c = numOrC; // C
|
||||
}
|
||||
if (typeof boolOrC !== "Object") {
|
||||
var r4 = boolOrC; // boolean | C
|
||||
var r4 = boolOrC; // boolean
|
||||
}
|
||||
else {
|
||||
c = boolOrC; // C
|
||||
|
||||
@ -56,9 +56,8 @@ if (typeof strOrC === "Object") {
|
||||
>strOrC : Symbol(strOrC, Decl(typeGuardOfFormTypeOfOther.ts, 9, 3))
|
||||
}
|
||||
else {
|
||||
var r2: string | C = strOrC; // string | C
|
||||
var r2: string = strOrC; // string
|
||||
>r2 : Symbol(r2, Decl(typeGuardOfFormTypeOfOther.ts, 24, 7), Decl(typeGuardOfFormTypeOfOther.ts, 51, 7))
|
||||
>C : Symbol(C, Decl(typeGuardOfFormTypeOfOther.ts, 0, 0))
|
||||
>strOrC : Symbol(strOrC, Decl(typeGuardOfFormTypeOfOther.ts, 9, 3))
|
||||
}
|
||||
if (typeof numOrC === "Object") {
|
||||
@ -69,9 +68,8 @@ if (typeof numOrC === "Object") {
|
||||
>numOrC : Symbol(numOrC, Decl(typeGuardOfFormTypeOfOther.ts, 10, 3))
|
||||
}
|
||||
else {
|
||||
var r3: number | C = numOrC; // number | C
|
||||
var r3: number = numOrC; // number
|
||||
>r3 : Symbol(r3, Decl(typeGuardOfFormTypeOfOther.ts, 30, 7), Decl(typeGuardOfFormTypeOfOther.ts, 57, 7))
|
||||
>C : Symbol(C, Decl(typeGuardOfFormTypeOfOther.ts, 0, 0))
|
||||
>numOrC : Symbol(numOrC, Decl(typeGuardOfFormTypeOfOther.ts, 10, 3))
|
||||
}
|
||||
if (typeof boolOrC === "Object") {
|
||||
@ -82,9 +80,8 @@ if (typeof boolOrC === "Object") {
|
||||
>boolOrC : Symbol(boolOrC, Decl(typeGuardOfFormTypeOfOther.ts, 11, 3))
|
||||
}
|
||||
else {
|
||||
var r4: boolean | C = boolOrC; // boolean | C
|
||||
var r4: boolean = boolOrC; // boolean
|
||||
>r4 : Symbol(r4, Decl(typeGuardOfFormTypeOfOther.ts, 36, 7), Decl(typeGuardOfFormTypeOfOther.ts, 63, 7))
|
||||
>C : Symbol(C, Decl(typeGuardOfFormTypeOfOther.ts, 0, 0))
|
||||
>boolOrC : Symbol(boolOrC, Decl(typeGuardOfFormTypeOfOther.ts, 11, 3))
|
||||
}
|
||||
|
||||
@ -108,9 +105,8 @@ else {
|
||||
if (typeof strOrC !== "Object") {
|
||||
>strOrC : Symbol(strOrC, Decl(typeGuardOfFormTypeOfOther.ts, 9, 3))
|
||||
|
||||
var r2: string | C = strOrC; // string | C
|
||||
var r2: string = strOrC; // string
|
||||
>r2 : Symbol(r2, Decl(typeGuardOfFormTypeOfOther.ts, 24, 7), Decl(typeGuardOfFormTypeOfOther.ts, 51, 7))
|
||||
>C : Symbol(C, Decl(typeGuardOfFormTypeOfOther.ts, 0, 0))
|
||||
>strOrC : Symbol(strOrC, Decl(typeGuardOfFormTypeOfOther.ts, 9, 3))
|
||||
}
|
||||
else {
|
||||
@ -121,9 +117,8 @@ else {
|
||||
if (typeof numOrC !== "Object") {
|
||||
>numOrC : Symbol(numOrC, Decl(typeGuardOfFormTypeOfOther.ts, 10, 3))
|
||||
|
||||
var r3: number | C = numOrC; // number | C
|
||||
var r3: number = numOrC; // number
|
||||
>r3 : Symbol(r3, Decl(typeGuardOfFormTypeOfOther.ts, 30, 7), Decl(typeGuardOfFormTypeOfOther.ts, 57, 7))
|
||||
>C : Symbol(C, Decl(typeGuardOfFormTypeOfOther.ts, 0, 0))
|
||||
>numOrC : Symbol(numOrC, Decl(typeGuardOfFormTypeOfOther.ts, 10, 3))
|
||||
}
|
||||
else {
|
||||
@ -134,9 +129,8 @@ else {
|
||||
if (typeof boolOrC !== "Object") {
|
||||
>boolOrC : Symbol(boolOrC, Decl(typeGuardOfFormTypeOfOther.ts, 11, 3))
|
||||
|
||||
var r4: boolean | C = boolOrC; // boolean | C
|
||||
var r4: boolean = boolOrC; // boolean
|
||||
>r4 : Symbol(r4, Decl(typeGuardOfFormTypeOfOther.ts, 36, 7), Decl(typeGuardOfFormTypeOfOther.ts, 63, 7))
|
||||
>C : Symbol(C, Decl(typeGuardOfFormTypeOfOther.ts, 0, 0))
|
||||
>boolOrC : Symbol(boolOrC, Decl(typeGuardOfFormTypeOfOther.ts, 11, 3))
|
||||
}
|
||||
else {
|
||||
|
||||
@ -60,10 +60,9 @@ if (typeof strOrC === "Object") {
|
||||
>strOrC : C
|
||||
}
|
||||
else {
|
||||
var r2: string | C = strOrC; // string | C
|
||||
>r2 : string | C
|
||||
>C : C
|
||||
>strOrC : string | C
|
||||
var r2: string = strOrC; // string
|
||||
>r2 : string
|
||||
>strOrC : string
|
||||
}
|
||||
if (typeof numOrC === "Object") {
|
||||
>typeof numOrC === "Object" : boolean
|
||||
@ -77,10 +76,9 @@ if (typeof numOrC === "Object") {
|
||||
>numOrC : C
|
||||
}
|
||||
else {
|
||||
var r3: number | C = numOrC; // number | C
|
||||
>r3 : number | C
|
||||
>C : C
|
||||
>numOrC : number | C
|
||||
var r3: number = numOrC; // number
|
||||
>r3 : number
|
||||
>numOrC : number
|
||||
}
|
||||
if (typeof boolOrC === "Object") {
|
||||
>typeof boolOrC === "Object" : boolean
|
||||
@ -94,10 +92,9 @@ if (typeof boolOrC === "Object") {
|
||||
>boolOrC : C
|
||||
}
|
||||
else {
|
||||
var r4: boolean | C = boolOrC; // boolean | C
|
||||
>r4 : boolean | C
|
||||
>C : C
|
||||
>boolOrC : boolean | C
|
||||
var r4: boolean = boolOrC; // boolean
|
||||
>r4 : boolean
|
||||
>boolOrC : boolean
|
||||
}
|
||||
|
||||
// Narrowing occurs only if target type is a subtype of variable type
|
||||
@ -126,10 +123,9 @@ if (typeof strOrC !== "Object") {
|
||||
>strOrC : string | C
|
||||
>"Object" : string
|
||||
|
||||
var r2: string | C = strOrC; // string | C
|
||||
>r2 : string | C
|
||||
>C : C
|
||||
>strOrC : string | C
|
||||
var r2: string = strOrC; // string
|
||||
>r2 : string
|
||||
>strOrC : string
|
||||
}
|
||||
else {
|
||||
c = strOrC; // C
|
||||
@ -143,10 +139,9 @@ if (typeof numOrC !== "Object") {
|
||||
>numOrC : number | C
|
||||
>"Object" : string
|
||||
|
||||
var r3: number | C = numOrC; // number | C
|
||||
>r3 : number | C
|
||||
>C : C
|
||||
>numOrC : number | C
|
||||
var r3: number = numOrC; // number
|
||||
>r3 : number
|
||||
>numOrC : number
|
||||
}
|
||||
else {
|
||||
c = numOrC; // C
|
||||
@ -160,10 +155,9 @@ if (typeof boolOrC !== "Object") {
|
||||
>boolOrC : boolean | C
|
||||
>"Object" : string
|
||||
|
||||
var r4: boolean | C = boolOrC; // boolean | C
|
||||
>r4 : boolean | C
|
||||
>C : C
|
||||
>boolOrC : boolean | C
|
||||
var r4: boolean = boolOrC; // boolean
|
||||
>r4 : boolean
|
||||
>boolOrC : boolean
|
||||
}
|
||||
else {
|
||||
c = boolOrC; // C
|
||||
|
||||
17
tests/baselines/reference/typeGuardRedundancy.js
Normal file
17
tests/baselines/reference/typeGuardRedundancy.js
Normal file
@ -0,0 +1,17 @@
|
||||
//// [typeGuardRedundancy.ts]
|
||||
var x: string|number;
|
||||
|
||||
var r1 = typeof x === "string" && typeof x === "string" ? x.substr : x.toFixed;
|
||||
|
||||
var r2 = !(typeof x === "string" && typeof x === "string") ? x.toFixed : x.substr;
|
||||
|
||||
var r3 = typeof x === "string" || typeof x === "string" ? x.substr : x.toFixed;
|
||||
|
||||
var r4 = !(typeof x === "string" || typeof x === "string") ? x.toFixed : x.substr;
|
||||
|
||||
//// [typeGuardRedundancy.js]
|
||||
var x;
|
||||
var r1 = typeof x === "string" && typeof x === "string" ? x.substr : x.toFixed;
|
||||
var r2 = !(typeof x === "string" && typeof x === "string") ? x.toFixed : x.substr;
|
||||
var r3 = typeof x === "string" || typeof x === "string" ? x.substr : x.toFixed;
|
||||
var r4 = !(typeof x === "string" || typeof x === "string") ? x.toFixed : x.substr;
|
||||
48
tests/baselines/reference/typeGuardRedundancy.symbols
Normal file
48
tests/baselines/reference/typeGuardRedundancy.symbols
Normal file
@ -0,0 +1,48 @@
|
||||
=== tests/cases/conformance/expressions/typeGuards/typeGuardRedundancy.ts ===
|
||||
var x: string|number;
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
|
||||
var r1 = typeof x === "string" && typeof x === "string" ? x.substr : x.toFixed;
|
||||
>r1 : Symbol(r1, Decl(typeGuardRedundancy.ts, 2, 3))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>x.substr : Symbol(String.substr, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>substr : Symbol(String.substr, Decl(lib.d.ts, --, --))
|
||||
>x.toFixed : Symbol(Number.toFixed, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>toFixed : Symbol(Number.toFixed, Decl(lib.d.ts, --, --))
|
||||
|
||||
var r2 = !(typeof x === "string" && typeof x === "string") ? x.toFixed : x.substr;
|
||||
>r2 : Symbol(r2, Decl(typeGuardRedundancy.ts, 4, 3))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>x.toFixed : Symbol(Number.toFixed, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>toFixed : Symbol(Number.toFixed, Decl(lib.d.ts, --, --))
|
||||
>x.substr : Symbol(String.substr, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>substr : Symbol(String.substr, Decl(lib.d.ts, --, --))
|
||||
|
||||
var r3 = typeof x === "string" || typeof x === "string" ? x.substr : x.toFixed;
|
||||
>r3 : Symbol(r3, Decl(typeGuardRedundancy.ts, 6, 3))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>x.substr : Symbol(String.substr, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>substr : Symbol(String.substr, Decl(lib.d.ts, --, --))
|
||||
>x.toFixed : Symbol(Number.toFixed, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>toFixed : Symbol(Number.toFixed, Decl(lib.d.ts, --, --))
|
||||
|
||||
var r4 = !(typeof x === "string" || typeof x === "string") ? x.toFixed : x.substr;
|
||||
>r4 : Symbol(r4, Decl(typeGuardRedundancy.ts, 8, 3))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>x.toFixed : Symbol(Number.toFixed, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>toFixed : Symbol(Number.toFixed, Decl(lib.d.ts, --, --))
|
||||
>x.substr : Symbol(String.substr, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(typeGuardRedundancy.ts, 0, 3))
|
||||
>substr : Symbol(String.substr, Decl(lib.d.ts, --, --))
|
||||
|
||||
84
tests/baselines/reference/typeGuardRedundancy.types
Normal file
84
tests/baselines/reference/typeGuardRedundancy.types
Normal file
@ -0,0 +1,84 @@
|
||||
=== tests/cases/conformance/expressions/typeGuards/typeGuardRedundancy.ts ===
|
||||
var x: string|number;
|
||||
>x : string | number
|
||||
|
||||
var r1 = typeof x === "string" && typeof x === "string" ? x.substr : x.toFixed;
|
||||
>r1 : (from: number, length?: number) => string
|
||||
>typeof x === "string" && typeof x === "string" ? x.substr : x.toFixed : (from: number, length?: number) => string
|
||||
>typeof x === "string" && typeof x === "string" : boolean
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>"string" : string
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string
|
||||
>"string" : string
|
||||
>x.substr : (from: number, length?: number) => string
|
||||
>x : string
|
||||
>substr : (from: number, length?: number) => string
|
||||
>x.toFixed : (fractionDigits?: number) => string
|
||||
>x : number
|
||||
>toFixed : (fractionDigits?: number) => string
|
||||
|
||||
var r2 = !(typeof x === "string" && typeof x === "string") ? x.toFixed : x.substr;
|
||||
>r2 : (fractionDigits?: number) => string
|
||||
>!(typeof x === "string" && typeof x === "string") ? x.toFixed : x.substr : (fractionDigits?: number) => string
|
||||
>!(typeof x === "string" && typeof x === "string") : boolean
|
||||
>(typeof x === "string" && typeof x === "string") : boolean
|
||||
>typeof x === "string" && typeof x === "string" : boolean
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>"string" : string
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string
|
||||
>"string" : string
|
||||
>x.toFixed : (fractionDigits?: number) => string
|
||||
>x : number
|
||||
>toFixed : (fractionDigits?: number) => string
|
||||
>x.substr : (from: number, length?: number) => string
|
||||
>x : string
|
||||
>substr : (from: number, length?: number) => string
|
||||
|
||||
var r3 = typeof x === "string" || typeof x === "string" ? x.substr : x.toFixed;
|
||||
>r3 : (from: number, length?: number) => string
|
||||
>typeof x === "string" || typeof x === "string" ? x.substr : x.toFixed : (from: number, length?: number) => string
|
||||
>typeof x === "string" || typeof x === "string" : boolean
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>"string" : string
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : number
|
||||
>"string" : string
|
||||
>x.substr : (from: number, length?: number) => string
|
||||
>x : string
|
||||
>substr : (from: number, length?: number) => string
|
||||
>x.toFixed : (fractionDigits?: number) => string
|
||||
>x : number
|
||||
>toFixed : (fractionDigits?: number) => string
|
||||
|
||||
var r4 = !(typeof x === "string" || typeof x === "string") ? x.toFixed : x.substr;
|
||||
>r4 : (fractionDigits?: number) => string
|
||||
>!(typeof x === "string" || typeof x === "string") ? x.toFixed : x.substr : (fractionDigits?: number) => string
|
||||
>!(typeof x === "string" || typeof x === "string") : boolean
|
||||
>(typeof x === "string" || typeof x === "string") : boolean
|
||||
>typeof x === "string" || typeof x === "string" : boolean
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>"string" : string
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : number
|
||||
>"string" : string
|
||||
>x.toFixed : (fractionDigits?: number) => string
|
||||
>x : number
|
||||
>toFixed : (fractionDigits?: number) => string
|
||||
>x.substr : (from: number, length?: number) => string
|
||||
>x : string
|
||||
>substr : (from: number, length?: number) => string
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
//// [typeGuardTautologicalConsistiency.ts]
|
||||
let stringOrNumber: string | number;
|
||||
|
||||
if (typeof stringOrNumber === "number") {
|
||||
if (typeof stringOrNumber !== "number") {
|
||||
stringOrNumber;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof stringOrNumber === "number" && typeof stringOrNumber !== "number") {
|
||||
stringOrNumber;
|
||||
}
|
||||
|
||||
|
||||
//// [typeGuardTautologicalConsistiency.js]
|
||||
var stringOrNumber;
|
||||
if (typeof stringOrNumber === "number") {
|
||||
if (typeof stringOrNumber !== "number") {
|
||||
stringOrNumber;
|
||||
}
|
||||
}
|
||||
if (typeof stringOrNumber === "number" && typeof stringOrNumber !== "number") {
|
||||
stringOrNumber;
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
=== tests/cases/conformance/expressions/typeGuards/typeGuardTautologicalConsistiency.ts ===
|
||||
let stringOrNumber: string | number;
|
||||
>stringOrNumber : Symbol(stringOrNumber, Decl(typeGuardTautologicalConsistiency.ts, 0, 3))
|
||||
|
||||
if (typeof stringOrNumber === "number") {
|
||||
>stringOrNumber : Symbol(stringOrNumber, Decl(typeGuardTautologicalConsistiency.ts, 0, 3))
|
||||
|
||||
if (typeof stringOrNumber !== "number") {
|
||||
>stringOrNumber : Symbol(stringOrNumber, Decl(typeGuardTautologicalConsistiency.ts, 0, 3))
|
||||
|
||||
stringOrNumber;
|
||||
>stringOrNumber : Symbol(stringOrNumber, Decl(typeGuardTautologicalConsistiency.ts, 0, 3))
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof stringOrNumber === "number" && typeof stringOrNumber !== "number") {
|
||||
>stringOrNumber : Symbol(stringOrNumber, Decl(typeGuardTautologicalConsistiency.ts, 0, 3))
|
||||
>stringOrNumber : Symbol(stringOrNumber, Decl(typeGuardTautologicalConsistiency.ts, 0, 3))
|
||||
|
||||
stringOrNumber;
|
||||
>stringOrNumber : Symbol(stringOrNumber, Decl(typeGuardTautologicalConsistiency.ts, 0, 3))
|
||||
}
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
=== tests/cases/conformance/expressions/typeGuards/typeGuardTautologicalConsistiency.ts ===
|
||||
let stringOrNumber: string | number;
|
||||
>stringOrNumber : string | number
|
||||
|
||||
if (typeof stringOrNumber === "number") {
|
||||
>typeof stringOrNumber === "number" : boolean
|
||||
>typeof stringOrNumber : string
|
||||
>stringOrNumber : string | number
|
||||
>"number" : string
|
||||
|
||||
if (typeof stringOrNumber !== "number") {
|
||||
>typeof stringOrNumber !== "number" : boolean
|
||||
>typeof stringOrNumber : string
|
||||
>stringOrNumber : number
|
||||
>"number" : string
|
||||
|
||||
stringOrNumber;
|
||||
>stringOrNumber : string | number
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof stringOrNumber === "number" && typeof stringOrNumber !== "number") {
|
||||
>typeof stringOrNumber === "number" && typeof stringOrNumber !== "number" : boolean
|
||||
>typeof stringOrNumber === "number" : boolean
|
||||
>typeof stringOrNumber : string
|
||||
>stringOrNumber : string | number
|
||||
>"number" : string
|
||||
>typeof stringOrNumber !== "number" : boolean
|
||||
>typeof stringOrNumber : string
|
||||
>stringOrNumber : number
|
||||
>"number" : string
|
||||
|
||||
stringOrNumber;
|
||||
>stringOrNumber : string | number
|
||||
}
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
enum E {}
|
||||
enum V {}
|
||||
|
||||
let x: number|string|E|V;
|
||||
|
||||
if (typeof x === "number") {
|
||||
x; // number|E|V
|
||||
}
|
||||
else {
|
||||
x; // string
|
||||
}
|
||||
|
||||
if (typeof x !== "number") {
|
||||
x; // string
|
||||
}
|
||||
else {
|
||||
x; // number|E|V
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
let strOrBool: string|boolean;
|
||||
if ((typeof strOrBool === 'boolean' && !strOrBool) || typeof strOrBool === 'string') {
|
||||
let label: string = (typeof strOrBool === 'string') ? strOrBool : "string";
|
||||
let bool: boolean = (typeof strOrBool === 'boolean') ? strOrBool : false;
|
||||
let label2: string = (typeof strOrBool !== 'boolean') ? strOrBool : "string";
|
||||
let bool2: boolean = (typeof strOrBool !== 'string') ? strOrBool : false;
|
||||
}
|
||||
|
||||
if ((typeof strOrBool !== 'string' && !strOrBool) || typeof strOrBool !== 'boolean') {
|
||||
let label: string = (typeof strOrBool === 'string') ? strOrBool : "string";
|
||||
let bool: boolean = (typeof strOrBool === 'boolean') ? strOrBool : false;
|
||||
let label2: string = (typeof strOrBool !== 'boolean') ? strOrBool : "string";
|
||||
let bool2: boolean = (typeof strOrBool !== 'string') ? strOrBool : false;
|
||||
}
|
||||
@ -22,19 +22,19 @@ if (typeof strOrC === "Object") {
|
||||
c = strOrC; // C
|
||||
}
|
||||
else {
|
||||
var r2: string | C = strOrC; // string | C
|
||||
var r2: string = strOrC; // string
|
||||
}
|
||||
if (typeof numOrC === "Object") {
|
||||
c = numOrC; // C
|
||||
}
|
||||
else {
|
||||
var r3: number | C = numOrC; // number | C
|
||||
var r3: number = numOrC; // number
|
||||
}
|
||||
if (typeof boolOrC === "Object") {
|
||||
c = boolOrC; // C
|
||||
}
|
||||
else {
|
||||
var r4: boolean | C = boolOrC; // boolean | C
|
||||
var r4: boolean = boolOrC; // boolean
|
||||
}
|
||||
|
||||
// Narrowing occurs only if target type is a subtype of variable type
|
||||
@ -49,19 +49,19 @@ else {
|
||||
// - when true, narrows the type of x by typeof x === s when false, or
|
||||
// - when false, narrows the type of x by typeof x === s when true.
|
||||
if (typeof strOrC !== "Object") {
|
||||
var r2: string | C = strOrC; // string | C
|
||||
var r2: string = strOrC; // string
|
||||
}
|
||||
else {
|
||||
c = strOrC; // C
|
||||
}
|
||||
if (typeof numOrC !== "Object") {
|
||||
var r3: number | C = numOrC; // number | C
|
||||
var r3: number = numOrC; // number
|
||||
}
|
||||
else {
|
||||
c = numOrC; // C
|
||||
}
|
||||
if (typeof boolOrC !== "Object") {
|
||||
var r4: boolean | C = boolOrC; // boolean | C
|
||||
var r4: boolean = boolOrC; // boolean
|
||||
}
|
||||
else {
|
||||
c = boolOrC; // C
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
var x: string|number;
|
||||
|
||||
var r1 = typeof x === "string" && typeof x === "string" ? x.substr : x.toFixed;
|
||||
|
||||
var r2 = !(typeof x === "string" && typeof x === "string") ? x.toFixed : x.substr;
|
||||
|
||||
var r3 = typeof x === "string" || typeof x === "string" ? x.substr : x.toFixed;
|
||||
|
||||
var r4 = !(typeof x === "string" || typeof x === "string") ? x.toFixed : x.substr;
|
||||
@ -0,0 +1,11 @@
|
||||
let stringOrNumber: string | number;
|
||||
|
||||
if (typeof stringOrNumber === "number") {
|
||||
if (typeof stringOrNumber !== "number") {
|
||||
stringOrNumber;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof stringOrNumber === "number" && typeof stringOrNumber !== "number") {
|
||||
stringOrNumber;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user