Merge pull request #11126 from Microsoft/nonWideningLiterals

Non-widening explicit literal types
This commit is contained in:
Anders Hejlsberg
2016-09-26 15:22:25 -07:00
committed by GitHub
48 changed files with 1448 additions and 231 deletions
+152 -45
View File
@@ -2015,6 +2015,10 @@ namespace ts {
isExternalModuleAugmentation(node.parent.parent);
}
function literalTypeToString(type: LiteralType) {
return type.flags & TypeFlags.StringLiteral ? `"${escapeString((<LiteralType>type).text)}"` : (<LiteralType>type).text;
}
function getSymbolDisplayBuilder(): SymbolDisplayBuilder {
function getNameOfSymbol(symbol: Symbol): string {
@@ -2190,11 +2194,8 @@ namespace ts {
else if (type.flags & TypeFlags.Anonymous) {
writeAnonymousType(<ObjectType>type, nextFlags);
}
else if (type.flags & TypeFlags.StringLiteral) {
writer.writeStringLiteral(`"${escapeString((<LiteralType>type).text)}"`);
}
else if (type.flags & TypeFlags.NumberLiteral) {
writer.writeStringLiteral((<LiteralType>type).text);
else if (type.flags & TypeFlags.StringOrNumberLiteral) {
writer.writeStringLiteral(literalTypeToString(<LiteralType>type));
}
else {
// Should never get here
@@ -3839,6 +3840,14 @@ namespace ts {
return true;
}
function createEnumLiteralType(symbol: Symbol, baseType: EnumType, text: string) {
const type = <EnumLiteralType>createType(TypeFlags.EnumLiteral);
type.symbol = symbol;
type.baseType = <EnumType & UnionType>baseType;
type.text = text;
return type;
}
function getDeclaredTypeOfEnum(symbol: Symbol): Type {
const links = getSymbolLinks(symbol);
if (!links.declaredType) {
@@ -3854,10 +3863,7 @@ namespace ts {
const memberSymbol = getSymbolOfNode(member);
const value = getEnumMemberValue(member);
if (!memberTypes[value]) {
const memberType = memberTypes[value] = <EnumLiteralType>createType(TypeFlags.EnumLiteral);
memberType.symbol = memberSymbol;
memberType.baseType = <EnumType & UnionType>enumType;
memberType.text = "" + value;
const memberType = memberTypes[value] = createEnumLiteralType(memberSymbol, enumType, "" + value);
memberTypeList.push(memberType);
}
}
@@ -5336,6 +5342,9 @@ namespace ts {
containsUndefined?: boolean;
containsNull?: boolean;
containsNonWideningType?: boolean;
containsString?: boolean;
containsNumber?: boolean;
containsStringOrNumberLiteral?: boolean;
}
function binarySearchTypes(types: Type[], type: Type): number {
@@ -5363,22 +5372,26 @@ namespace ts {
}
function addTypeToUnion(typeSet: TypeSet, type: Type) {
if (type.flags & TypeFlags.Union) {
const flags = type.flags;
if (flags & TypeFlags.Union) {
addTypesToUnion(typeSet, (<UnionType>type).types);
}
else if (type.flags & TypeFlags.Any) {
else if (flags & TypeFlags.Any) {
typeSet.containsAny = true;
}
else if (!strictNullChecks && type.flags & TypeFlags.Nullable) {
if (type.flags & TypeFlags.Undefined) typeSet.containsUndefined = true;
if (type.flags & TypeFlags.Null) typeSet.containsNull = true;
if (!(type.flags & TypeFlags.ContainsWideningType)) typeSet.containsNonWideningType = true;
else if (!strictNullChecks && flags & TypeFlags.Nullable) {
if (flags & TypeFlags.Undefined) typeSet.containsUndefined = true;
if (flags & TypeFlags.Null) typeSet.containsNull = true;
if (!(flags & TypeFlags.ContainsWideningType)) typeSet.containsNonWideningType = true;
}
else if (!(type.flags & TypeFlags.Never)) {
else if (!(flags & TypeFlags.Never)) {
if (flags & TypeFlags.String) typeSet.containsString = true;
if (flags & TypeFlags.Number) typeSet.containsNumber = true;
if (flags & TypeFlags.StringOrNumberLiteral) typeSet.containsStringOrNumberLiteral = true;
const len = typeSet.length;
const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearchTypes(typeSet, type);
if (index < 0) {
if (!(type.flags & TypeFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && containsIdenticalType(typeSet, type))) {
if (!(flags & TypeFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && containsIdenticalType(typeSet, type))) {
typeSet.splice(~index, 0, type);
}
}
@@ -5411,7 +5424,7 @@ namespace ts {
return false;
}
function removeSubtypes(types: Type[]) {
function removeSubtypes(types: TypeSet) {
let i = types.length;
while (i > 0) {
i--;
@@ -5421,6 +5434,21 @@ namespace ts {
}
}
function removeRedundantLiteralTypes(types: TypeSet) {
let i = types.length;
while (i > 0) {
i--;
const t = types[i];
const remove =
t.flags & TypeFlags.StringLiteral && types.containsString ||
t.flags & TypeFlags.NumberLiteral && types.containsNumber ||
t.flags & TypeFlags.StringOrNumberLiteral && t.flags & TypeFlags.FreshLiteral && containsType(types, (<LiteralType>t).regularType);
if (remove) {
orderedRemoveItemAt(types, i);
}
}
}
// We sort and deduplicate the constituent types based on object identity. If the subtypeReduction
// flag is specified we also reduce the constituent type set to only include types that aren't subtypes
// of other types. Subtype reduction is expensive for large union types and is possible only when union
@@ -5443,6 +5471,9 @@ namespace ts {
if (subtypeReduction) {
removeSubtypes(typeSet);
}
else if (typeSet.containsStringOrNumberLiteral) {
removeRedundantLiteralTypes(typeSet);
}
if (typeSet.length === 0) {
return typeSet.containsNull ? typeSet.containsNonWideningType ? nullType : nullWideningType :
typeSet.containsUndefined ? typeSet.containsNonWideningType ? undefinedType : undefinedWideningType :
@@ -5554,6 +5585,22 @@ namespace ts {
return type;
}
function getFreshTypeOfLiteralType(type: Type) {
if (type.flags & TypeFlags.StringOrNumberLiteral && !(type.flags & TypeFlags.FreshLiteral)) {
if (!(<LiteralType>type).freshType) {
const freshType = <LiteralType>createLiteralType(type.flags | TypeFlags.FreshLiteral, (<LiteralType>type).text);
freshType.regularType = <LiteralType>type;
(<LiteralType>type).freshType = freshType;
}
return (<LiteralType>type).freshType;
}
return type;
}
function getRegularTypeOfLiteralType(type: Type) {
return type.flags & TypeFlags.StringOrNumberLiteral && type.flags & TypeFlags.FreshLiteral ? (<LiteralType>type).regularType : type;
}
function getLiteralTypeForText(flags: TypeFlags, text: string) {
const map = flags & TypeFlags.StringLiteral ? stringLiteralTypes : numericLiteralTypes;
return map[text] || (map[text] = createLiteralType(flags, text));
@@ -5562,7 +5609,7 @@ namespace ts {
function getTypeFromLiteralTypeNode(node: LiteralTypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
links.resolvedType = checkExpression(node.literal);
links.resolvedType = getRegularTypeOfLiteralType(checkExpression(node.literal));
}
return links.resolvedType;
}
@@ -6274,7 +6321,7 @@ namespace ts {
if ((source.flags & TypeFlags.Number | source.flags & TypeFlags.NumberLiteral) && target.flags & TypeFlags.EnumLike) return true;
if (source.flags & TypeFlags.EnumLiteral &&
target.flags & TypeFlags.EnumLiteral &&
(<LiteralType>source).text === (<LiteralType>target).text &&
(<EnumLiteralType>source).text === (<EnumLiteralType>target).text &&
isEnumTypeRelatedTo((<EnumLiteralType>source).baseType, (<EnumLiteralType>target).baseType, errorReporter)) {
return true;
}
@@ -6288,6 +6335,12 @@ namespace ts {
}
function isTypeRelatedTo(source: Type, target: Type, relation: Map<RelationComparisonResult>) {
if (source.flags & TypeFlags.StringOrNumberLiteral && source.flags & TypeFlags.FreshLiteral) {
source = (<LiteralType>source).regularType;
}
if (target.flags & TypeFlags.StringOrNumberLiteral && target.flags & TypeFlags.FreshLiteral) {
target = (<LiteralType>target).regularType;
}
if (source === target || relation !== identityRelation && isSimpleTypeRelatedTo(source, target, relation)) {
return true;
}
@@ -6385,6 +6438,12 @@ namespace ts {
// Ternary.False if they are not related.
function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage): Ternary {
let result: Ternary;
if (source.flags & TypeFlags.StringOrNumberLiteral && source.flags & TypeFlags.FreshLiteral) {
source = (<LiteralType>source).regularType;
}
if (target.flags & TypeFlags.StringOrNumberLiteral && target.flags & TypeFlags.FreshLiteral) {
target = (<LiteralType>target).regularType;
}
// both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases
if (source === target) return Ternary.True;
@@ -6394,7 +6453,7 @@ namespace ts {
if (isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True;
if (source.flags & TypeFlags.FreshObjectLiteral) {
if (source.flags & TypeFlags.ObjectLiteral && source.flags & TypeFlags.FreshLiteral) {
if (hasExcessProperties(<FreshObjectLiteralType>source, target, reportErrors)) {
if (reportErrors) {
reportRelationError(headMessage, source, target);
@@ -7303,6 +7362,15 @@ namespace ts {
type;
}
function getWidenedLiteralType(type: Type): Type {
return type.flags & TypeFlags.StringLiteral && type.flags & TypeFlags.FreshLiteral ? stringType :
type.flags & TypeFlags.NumberLiteral && type.flags & TypeFlags.FreshLiteral ? numberType :
type.flags & TypeFlags.BooleanLiteral ? booleanType :
type.flags & TypeFlags.EnumLiteral ? (<EnumLiteralType>type).baseType :
type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(map((<UnionType>type).types, getWidenedLiteralType)) :
type;
}
/**
* Check if a Type was written as a tuple type literal.
* Prefer using isTupleLikeType() unless the use of `elementTypes` is required.
@@ -7324,8 +7392,8 @@ namespace ts {
// no flags for all other types (including non-falsy literal types).
function getFalsyFlags(type: Type): TypeFlags {
return type.flags & TypeFlags.Union ? getFalsyFlagsOfTypes((<UnionType>type).types) :
type.flags & TypeFlags.StringLiteral ? type === emptyStringType ? TypeFlags.StringLiteral : 0 :
type.flags & TypeFlags.NumberLiteral ? type === zeroType ? TypeFlags.NumberLiteral : 0 :
type.flags & TypeFlags.StringLiteral ? (<LiteralType>type).text === "" ? TypeFlags.StringLiteral : 0 :
type.flags & TypeFlags.NumberLiteral ? (<LiteralType>type).text === "0" ? TypeFlags.NumberLiteral : 0 :
type.flags & TypeFlags.BooleanLiteral ? type === falseType ? TypeFlags.BooleanLiteral : 0 :
type.flags & TypeFlags.PossiblyFalsy;
}
@@ -7392,7 +7460,7 @@ namespace ts {
* Leave signatures alone since they are not subject to the check.
*/
function getRegularTypeOfObjectLiteral(type: Type): Type {
if (!(type.flags & TypeFlags.FreshObjectLiteral)) {
if (!(type.flags & TypeFlags.ObjectLiteral && type.flags & TypeFlags.FreshLiteral)) {
return type;
}
const regularType = (<FreshObjectLiteralType>type).regularType;
@@ -7408,7 +7476,7 @@ namespace ts {
resolved.constructSignatures,
resolved.stringIndexInfo,
resolved.numberIndexInfo);
regularNew.flags = resolved.flags & ~TypeFlags.FreshObjectLiteral;
regularNew.flags = resolved.flags & ~TypeFlags.FreshLiteral;
(<FreshObjectLiteralType>type).regularType = regularNew;
return regularNew;
}
@@ -7859,7 +7927,7 @@ namespace ts {
const widenLiteralTypes = context.inferences[index].topLevel &&
!hasPrimitiveConstraint(signature.typeParameters[index]) &&
(context.inferences[index].isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), signature.typeParameters[index]));
const baseInferences = widenLiteralTypes ? map(inferences, getBaseTypeOfLiteralType) : inferences;
const baseInferences = widenLiteralTypes ? map(inferences, getWidenedLiteralType) : inferences;
// Infer widened union or supertype, or the unknown type for no common supertype
const unionOrSuperType = context.inferUnionTypes ? getUnionType(baseInferences, /*subtypeReduction*/ true) : getCommonSupertype(baseInferences);
inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType;
@@ -8110,14 +8178,14 @@ namespace ts {
}
if (flags & TypeFlags.StringLiteral) {
return strictNullChecks ?
type === emptyStringType ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts :
type === emptyStringType ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts;
(<LiteralType>type).text === "" ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts :
(<LiteralType>type).text === "" ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts;
}
if (flags & (TypeFlags.Number | TypeFlags.Enum)) {
return strictNullChecks ? TypeFacts.NumberStrictFacts : TypeFacts.NumberFacts;
}
if (flags & (TypeFlags.NumberLiteral | TypeFlags.EnumLiteral)) {
const isZero = type === zeroType || type.flags & TypeFlags.EnumLiteral && (<LiteralType>type).text === "0";
const isZero = (<LiteralType>type).text === "0";
return strictNullChecks ?
isZero ? TypeFacts.ZeroStrictFacts : TypeFacts.NonZeroStrictFacts :
isZero ? TypeFacts.ZeroFacts : TypeFacts.NonZeroFacts;
@@ -8290,7 +8358,7 @@ namespace ts {
function getTypeOfSwitchClause(clause: CaseClause | DefaultClause) {
if (clause.kind === SyntaxKind.CaseClause) {
const caseType = checkExpression((<CaseClause>clause).expression);
const caseType = getRegularTypeOfLiteralType(checkExpression((<CaseClause>clause).expression));
return isUnitType(caseType) ? caseType : undefined;
}
return neverType;
@@ -8671,7 +8739,11 @@ namespace ts {
const narrowedType = filterType(type, t => areTypesComparable(t, valueType));
return narrowedType.flags & TypeFlags.Never ? type : narrowedType;
}
return isUnitType(valueType) ? filterType(type, t => t !== valueType) : type;
if (isUnitType(valueType)) {
const regularType = getRegularTypeOfLiteralType(valueType);
return filterType(type, t => getRegularTypeOfLiteralType(t) !== regularType);
}
return type;
}
function narrowTypeByTypeof(type: Type, typeOfExpr: TypeOfExpression, operator: SyntaxKind, literal: LiteralExpression, assumeTrue: boolean): Type {
@@ -8716,7 +8788,7 @@ namespace ts {
if (!hasDefaultClause) {
return caseType;
}
const defaultType = filterType(type, t => !(isUnitType(t) && contains(switchTypes, t)));
const defaultType = filterType(type, t => !(isUnitType(t) && contains(switchTypes, getRegularTypeOfLiteralType(t))));
return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]);
}
@@ -9551,14 +9623,14 @@ namespace ts {
if (parameter.dotDotDotToken) {
const restTypes: Type[] = [];
for (let i = indexOfParameter; i < iife.arguments.length; i++) {
restTypes.push(getBaseTypeOfLiteralType(checkExpression(iife.arguments[i])));
restTypes.push(getWidenedLiteralType(checkExpression(iife.arguments[i])));
}
return createArrayType(getUnionType(restTypes));
}
const links = getNodeLinks(iife);
const cached = links.resolvedSignature;
links.resolvedSignature = anySignature;
const type = getBaseTypeOfLiteralType(checkExpression(iife.arguments[indexOfParameter]));
const type = getWidenedLiteralType(checkExpression(iife.arguments[indexOfParameter]));
links.resolvedSignature = cached;
return type;
}
@@ -10290,7 +10362,7 @@ namespace ts {
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined;
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined;
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshObjectLiteral;
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags) | (patternWithComputedProperties ? TypeFlags.ObjectLiteralPatternWithComputedProperties : 0);
if (inDestructuringPattern) {
result.pattern = node;
@@ -12660,7 +12732,7 @@ namespace ts {
reportErrorsFromWidening(func, type);
}
if (isUnitType(type) && !(contextualSignature && isLiteralContextualType(getReturnTypeOfSignature(contextualSignature)))) {
type = getBaseTypeOfLiteralType(type);
type = getWidenedLiteralType(type);
}
const widenedType = getWidenedType(type);
@@ -13044,7 +13116,7 @@ namespace ts {
return silentNeverType;
}
if (node.operator === SyntaxKind.MinusToken && node.operand.kind === SyntaxKind.NumericLiteral) {
return getLiteralTypeForText(TypeFlags.NumberLiteral, "" + -(<LiteralExpression>node.operand).text);
return getFreshTypeOfLiteralType(getLiteralTypeForText(TypeFlags.NumberLiteral, "" + -(<LiteralExpression>node.operand).text));
}
switch (node.operator) {
case SyntaxKind.PlusToken:
@@ -13683,12 +13755,13 @@ namespace ts {
}
switch (node.kind) {
case SyntaxKind.StringLiteral:
return getLiteralTypeForText(TypeFlags.StringLiteral, (<LiteralExpression>node).text);
return getFreshTypeOfLiteralType(getLiteralTypeForText(TypeFlags.StringLiteral, (<LiteralExpression>node).text));
case SyntaxKind.NumericLiteral:
return getLiteralTypeForText(TypeFlags.NumberLiteral, (<LiteralExpression>node).text);
return getFreshTypeOfLiteralType(getLiteralTypeForText(TypeFlags.NumberLiteral, (<LiteralExpression>node).text));
case SyntaxKind.TrueKeyword:
return trueType;
case SyntaxKind.FalseKeyword:
return node.kind === SyntaxKind.TrueKeyword ? trueType : falseType;
return falseType;
}
}
@@ -13736,7 +13809,7 @@ namespace ts {
const type = checkExpressionCached(declaration.initializer);
return getCombinedNodeFlags(declaration) & NodeFlags.Const ||
getCombinedModifierFlags(declaration) & ModifierFlags.Readonly ||
isTypeAssertion(declaration.initializer) ? type : getBaseTypeOfLiteralType(type);
isTypeAssertion(declaration.initializer) ? type : getWidenedLiteralType(type);
}
function isLiteralContextualType(contextualType: Type) {
@@ -13758,7 +13831,7 @@ namespace ts {
function checkExpressionForMutableLocation(node: Expression, contextualMapper?: TypeMapper): Type {
const type = checkExpression(node, contextualMapper);
return isTypeAssertion(node) || isLiteralContextualType(getContextualType(node)) ? type : getBaseTypeOfLiteralType(type);
return isTypeAssertion(node) || isLiteralContextualType(getContextualType(node)) ? type : getWidenedLiteralType(type);
}
function checkPropertyAssignment(node: PropertyAssignment, contextualMapper?: TypeMapper): Type {
@@ -18473,7 +18546,7 @@ namespace ts {
if (isRightSideOfQualifiedNameOrPropertyAccess(expr)) {
expr = <Expression>expr.parent;
}
return checkExpression(expr);
return getRegularTypeOfLiteralType(checkExpression(expr));
}
/**
@@ -18884,7 +18957,7 @@ namespace ts {
// Get type of the symbol if this is the valid symbol otherwise get type at location
const symbol = getSymbolOfNode(declaration);
const type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature))
? getTypeOfSymbol(symbol)
? getWidenedLiteralType(getTypeOfSymbol(symbol))
: unknownType;
getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags);
@@ -18944,6 +19017,19 @@ namespace ts {
return undefined;
}
function isLiteralConstDeclaration(node: VariableDeclaration): boolean {
if (isConst(node)) {
const type = getTypeOfSymbol(getSymbolOfNode(node));
return !!(type.flags & TypeFlags.StringOrNumberLiteral && type.flags & TypeFlags.FreshLiteral);
}
return false;
}
function writeLiteralConstValue(node: VariableDeclaration, writer: SymbolWriter) {
const type = getTypeOfSymbol(getSymbolOfNode(node));
writer.writeStringLiteral(literalTypeToString(<LiteralType>type));
}
function createResolver(): EmitResolver {
// this variable and functions that use it are deliberately moved here from the outer scope
// to avoid scope pollution
@@ -18988,7 +19074,9 @@ namespace ts {
isArgumentsLocalBinding,
getExternalModuleFileFromDeclaration,
getTypeReferenceDirectivesForEntityName,
getTypeReferenceDirectivesForSymbol
getTypeReferenceDirectivesForSymbol,
isLiteralConstDeclaration,
writeLiteralConstValue
};
// defined here to avoid outer scope pollution
@@ -20134,10 +20222,29 @@ namespace ts {
}
}
function isStringOrNumberLiteralExpression(expr: Expression) {
return expr.kind === SyntaxKind.StringLiteral || expr.kind === SyntaxKind.NumericLiteral ||
expr.kind === SyntaxKind.PrefixUnaryExpression && (<PrefixUnaryExpression>expr).operator === SyntaxKind.MinusToken &&
(<PrefixUnaryExpression>expr).operand.kind === SyntaxKind.NumericLiteral;
}
function checkGrammarVariableDeclaration(node: VariableDeclaration) {
if (node.parent.parent.kind !== SyntaxKind.ForInStatement && node.parent.parent.kind !== SyntaxKind.ForOfStatement) {
if (isInAmbientContext(node)) {
if (node.initializer) {
if (isConst(node) && !node.type) {
if (!isStringOrNumberLiteralExpression(node.initializer)) {
return grammarErrorOnNode(node.initializer, Diagnostics.A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal);
}
}
else {
// Error on equals token which immediate precedes the initializer
const equalsTokenLength = "=".length;
return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - equalsTokenLength,
equalsTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
}
}
if (node.initializer && !(isConst(node) && isStringOrNumberLiteralExpression(node.initializer))) {
// Error on equals token which immediate precedes the initializer
const equalsTokenLength = "=".length;
return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - equalsTokenLength,
+4
View File
@@ -1142,6 +1142,10 @@ namespace ts {
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && node.parent.kind === SyntaxKind.TypeLiteral) {
emitTypeOfVariableDeclarationFromTypeLiteral(node);
}
else if (resolver.isLiteralConstDeclaration(node)) {
write(" = ");
resolver.writeLiteralConstValue(node, writer);
}
else if (!hasModifier(node, ModifierFlags.Private)) {
writeTypeOfDeclaration(node, node.type, getVariableDeclarationTypeVisibilityError);
}
+4
View File
@@ -819,6 +819,10 @@
"category": "Error",
"code": 1253
},
"A 'const' initializer in an ambient context must be a string or numeric literal.": {
"category": "Error",
"code": 1254
},
"'with' statements are not allowed in an async function block.": {
"category": "Error",
"code": 1300
+10 -4
View File
@@ -2167,6 +2167,8 @@ namespace ts {
getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration): SourceFile;
getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): string[];
getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): string[];
isLiteralConstDeclaration(node: VariableDeclaration): boolean;
writeLiteralConstValue(node: VariableDeclaration, writer: SymbolWriter): void;
}
export const enum SymbolFlags {
@@ -2383,7 +2385,7 @@ namespace ts {
/* @internal */
ObjectLiteral = 1 << 23, // Originates in an object literal
/* @internal */
FreshObjectLiteral = 1 << 24, // Fresh object literal type
FreshLiteral = 1 << 24, // Fresh literal type
/* @internal */
ContainsWideningType = 1 << 25, // Type is or contains undefined or null widening type
/* @internal */
@@ -2396,6 +2398,7 @@ namespace ts {
/* @internal */
Nullable = Undefined | Null,
Literal = StringLiteral | NumberLiteral | BooleanLiteral | EnumLiteral,
StringOrNumberLiteral = StringLiteral | NumberLiteral,
/* @internal */
DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null,
PossiblyFalsy = DefinitelyFalsy | String | Number | Boolean,
@@ -2437,12 +2440,15 @@ namespace ts {
/* @internal */
// Intrinsic types (TypeFlags.Intrinsic)
export interface IntrinsicType extends Type {
intrinsicName: string; // Name of intrinsic type
intrinsicName: string; // Name of intrinsic type
}
// String literal types (TypeFlags.StringLiteral)
// Numeric literal types (TypeFlags.NumberLiteral)
export interface LiteralType extends Type {
text: string; // Text of string literal
text: string; // Text of literal
freshType?: LiteralType; // Fresh version of type
regularType?: LiteralType; // Regular version of type
}
// Enum types (TypeFlags.Enum)
@@ -2452,7 +2458,7 @@ namespace ts {
// Enum types (TypeFlags.EnumLiteral)
export interface EnumLiteralType extends LiteralType {
baseType: EnumType & UnionType;
baseType: EnumType & UnionType; // Base enum type
}
// Object types (TypeFlags.ObjectType)
@@ -0,0 +1,72 @@
//// [ambientConstLiterals.ts]
function f<T>(x: T): T {
return x;
}
enum E { A, B, C }
const c1 = "abc";
const c2 = 123;
const c3 = c1;
const c4 = c2;
const c5 = f(123);
const c6 = f(-123);
const c7 = true;
const c8 = E.A;
const c9 = { x: "abc" };
const c10 = [123];
const c11 = "abc" + "def";
const c12 = 123 + 456;
const c13 = Math.random() > 0.5 ? "abc" : "def";
const c14 = Math.random() > 0.5 ? 123 : 456;
//// [ambientConstLiterals.js]
function f(x) {
return x;
}
var E;
(function (E) {
E[E["A"] = 0] = "A";
E[E["B"] = 1] = "B";
E[E["C"] = 2] = "C";
})(E || (E = {}));
var c1 = "abc";
var c2 = 123;
var c3 = c1;
var c4 = c2;
var c5 = f(123);
var c6 = f(-123);
var c7 = true;
var c8 = E.A;
var c9 = { x: "abc" };
var c10 = [123];
var c11 = "abc" + "def";
var c12 = 123 + 456;
var c13 = Math.random() > 0.5 ? "abc" : "def";
var c14 = Math.random() > 0.5 ? 123 : 456;
//// [ambientConstLiterals.d.ts]
declare function f<T>(x: T): T;
declare enum E {
A = 0,
B = 1,
C = 2,
}
declare const c1 = "abc";
declare const c2 = 123;
declare const c3 = "abc";
declare const c4 = 123;
declare const c5 = 123;
declare const c6 = -123;
declare const c7: boolean;
declare const c8: E;
declare const c9: {
x: string;
};
declare const c10: number[];
declare const c11: string;
declare const c12: number;
declare const c13: string;
declare const c14: number;
@@ -0,0 +1,75 @@
=== tests/cases/compiler/ambientConstLiterals.ts ===
function f<T>(x: T): T {
>f : Symbol(f, Decl(ambientConstLiterals.ts, 0, 0))
>T : Symbol(T, Decl(ambientConstLiterals.ts, 1, 11))
>x : Symbol(x, Decl(ambientConstLiterals.ts, 1, 14))
>T : Symbol(T, Decl(ambientConstLiterals.ts, 1, 11))
>T : Symbol(T, Decl(ambientConstLiterals.ts, 1, 11))
return x;
>x : Symbol(x, Decl(ambientConstLiterals.ts, 1, 14))
}
enum E { A, B, C }
>E : Symbol(E, Decl(ambientConstLiterals.ts, 3, 1))
>A : Symbol(E.A, Decl(ambientConstLiterals.ts, 5, 8))
>B : Symbol(E.B, Decl(ambientConstLiterals.ts, 5, 11))
>C : Symbol(E.C, Decl(ambientConstLiterals.ts, 5, 14))
const c1 = "abc";
>c1 : Symbol(c1, Decl(ambientConstLiterals.ts, 7, 5))
const c2 = 123;
>c2 : Symbol(c2, Decl(ambientConstLiterals.ts, 8, 5))
const c3 = c1;
>c3 : Symbol(c3, Decl(ambientConstLiterals.ts, 9, 5))
>c1 : Symbol(c1, Decl(ambientConstLiterals.ts, 7, 5))
const c4 = c2;
>c4 : Symbol(c4, Decl(ambientConstLiterals.ts, 10, 5))
>c2 : Symbol(c2, Decl(ambientConstLiterals.ts, 8, 5))
const c5 = f(123);
>c5 : Symbol(c5, Decl(ambientConstLiterals.ts, 11, 5))
>f : Symbol(f, Decl(ambientConstLiterals.ts, 0, 0))
const c6 = f(-123);
>c6 : Symbol(c6, Decl(ambientConstLiterals.ts, 12, 5))
>f : Symbol(f, Decl(ambientConstLiterals.ts, 0, 0))
const c7 = true;
>c7 : Symbol(c7, Decl(ambientConstLiterals.ts, 13, 5))
const c8 = E.A;
>c8 : Symbol(c8, Decl(ambientConstLiterals.ts, 14, 5))
>E.A : Symbol(E.A, Decl(ambientConstLiterals.ts, 5, 8))
>E : Symbol(E, Decl(ambientConstLiterals.ts, 3, 1))
>A : Symbol(E.A, Decl(ambientConstLiterals.ts, 5, 8))
const c9 = { x: "abc" };
>c9 : Symbol(c9, Decl(ambientConstLiterals.ts, 15, 5))
>x : Symbol(x, Decl(ambientConstLiterals.ts, 15, 12))
const c10 = [123];
>c10 : Symbol(c10, Decl(ambientConstLiterals.ts, 16, 5))
const c11 = "abc" + "def";
>c11 : Symbol(c11, Decl(ambientConstLiterals.ts, 17, 5))
const c12 = 123 + 456;
>c12 : Symbol(c12, Decl(ambientConstLiterals.ts, 18, 5))
const c13 = Math.random() > 0.5 ? "abc" : "def";
>c13 : Symbol(c13, Decl(ambientConstLiterals.ts, 19, 5))
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))
const c14 = Math.random() > 0.5 ? 123 : 456;
>c14 : Symbol(c14, Decl(ambientConstLiterals.ts, 20, 5))
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))
@@ -0,0 +1,105 @@
=== tests/cases/compiler/ambientConstLiterals.ts ===
function f<T>(x: T): T {
>f : <T>(x: T) => T
>T : T
>x : T
>T : T
>T : T
return x;
>x : T
}
enum E { A, B, C }
>E : E
>A : E.A
>B : E.B
>C : E.C
const c1 = "abc";
>c1 : "abc"
>"abc" : "abc"
const c2 = 123;
>c2 : 123
>123 : 123
const c3 = c1;
>c3 : "abc"
>c1 : "abc"
const c4 = c2;
>c4 : 123
>c2 : 123
const c5 = f(123);
>c5 : 123
>f(123) : 123
>f : <T>(x: T) => T
>123 : 123
const c6 = f(-123);
>c6 : -123
>f(-123) : -123
>f : <T>(x: T) => T
>-123 : -123
>123 : 123
const c7 = true;
>c7 : true
>true : true
const c8 = E.A;
>c8 : E.A
>E.A : E.A
>E : typeof E
>A : E.A
const c9 = { x: "abc" };
>c9 : { x: string; }
>{ x: "abc" } : { x: string; }
>x : string
>"abc" : "abc"
const c10 = [123];
>c10 : number[]
>[123] : number[]
>123 : 123
const c11 = "abc" + "def";
>c11 : string
>"abc" + "def" : string
>"abc" : "abc"
>"def" : "def"
const c12 = 123 + 456;
>c12 : number
>123 + 456 : number
>123 : 123
>456 : 456
const c13 = Math.random() > 0.5 ? "abc" : "def";
>c13 : "abc" | "def"
>Math.random() > 0.5 ? "abc" : "def" : "abc" | "def"
>Math.random() > 0.5 : boolean
>Math.random() : number
>Math.random : () => number
>Math : Math
>random : () => number
>0.5 : 0.5
>"abc" : "abc"
>"def" : "def"
const c14 = Math.random() > 0.5 ? 123 : 456;
>c14 : 123 | 456
>Math.random() > 0.5 ? 123 : 456 : 123 | 456
>Math.random() > 0.5 : boolean
>Math.random() : number
>Math.random : () => number
>Math : Math
>random : () => number
>0.5 : 0.5
>123 : 123
>456 : 456
+1 -1
View File
@@ -46,7 +46,7 @@ class parser {
>this : this
>options : IOptions[]
>sort : (compareFn?: (a: IOptions, b: IOptions) => number) => IOptions[]
>function(a, b) { var aName = a.name.toLowerCase(); var bName = b.name.toLowerCase(); if (aName > bName) { return 1; } else if (aName < bName) { return -1; } else { return 0; } } : (a: IOptions, b: IOptions) => 0 | 1 | -1
>function(a, b) { var aName = a.name.toLowerCase(); var bName = b.name.toLowerCase(); if (aName > bName) { return 1; } else if (aName < bName) { return -1; } else { return 0; } } : (a: IOptions, b: IOptions) => 1 | -1 | 0
>a : IOptions
>b : IOptions
@@ -30,7 +30,7 @@ var derived2: Derived2;
var r2 = true ? 1 : '';
>r2 : string | number
>true ? 1 : '' : "" | 1
>true ? 1 : '' : 1 | ""
>true : true
>1 : 1
>'' : ""
@@ -19,7 +19,7 @@ declare function foo<T>(obj: I<T>): T
foo({
>foo({ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]}) : string | number | boolean | (() => void) | number[]
>foo : <T>(obj: I<T>) => T
>{ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]} : { [x: string]: true | "" | 0 | (() => void) | number[]; [x: number]: 0 | (() => void) | number[]; 0: () => void; p: ""; }
>{ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]} : { [x: string]: true | "" | (() => void) | 0 | number[]; [x: number]: (() => void) | 0 | number[]; 0: () => void; p: ""; }
p: "",
>p : string
@@ -19,7 +19,7 @@ declare function foo<T>(obj: I<T>): T
foo({
>foo({ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]}) : string | number | boolean | (() => void) | number[]
>foo : <T>(obj: I<T>) => T
>{ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]} : { [x: string]: true | "" | 0 | (() => void) | number[]; [x: number]: 0 | (() => void) | number[]; 0: () => void; p: ""; }
>{ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]} : { [x: string]: true | "" | (() => void) | 0 | number[]; [x: number]: (() => void) | 0 | number[]; 0: () => void; p: ""; }
p: "",
>p : string
@@ -1,9 +1,9 @@
tests/cases/compiler/conditionalExpression1.ts(1,5): error TS2322: Type '"" | 1' is not assignable to type 'boolean'.
Type '""' is not assignable to type 'boolean'.
tests/cases/compiler/conditionalExpression1.ts(1,5): error TS2322: Type '1 | ""' is not assignable to type 'boolean'.
Type '1' is not assignable to type 'boolean'.
==== tests/cases/compiler/conditionalExpression1.ts (1 errors) ====
var x: boolean = (true ? 1 : ""); // should be an error
~
!!! error TS2322: Type '"" | 1' is not assignable to type 'boolean'.
!!! error TS2322: Type '""' is not assignable to type 'boolean'.
!!! error TS2322: Type '1 | ""' is not assignable to type 'boolean'.
!!! error TS2322: Type '1' is not assignable to type 'boolean'.
@@ -16,7 +16,7 @@ var b = false ? undefined : 0;
var c = false ? 1 : 0;
>c : number
>false ? 1 : 0 : 0 | 1
>false ? 1 : 0 : 1 | 0
>false : false
>1 : 1
>0 : 0
@@ -1,13 +1,12 @@
tests/cases/compiler/constDeclarations-ambient-errors.ts(3,27): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(4,26): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(5,18): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(5,20): error TS1254: A 'const' initializer in an ambient context must be a string or numeric literal.
tests/cases/compiler/constDeclarations-ambient-errors.ts(5,37): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(5,51): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(8,14): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(9,22): error TS1039: Initializers are not allowed in ambient contexts.
==== tests/cases/compiler/constDeclarations-ambient-errors.ts (7 errors) ====
==== tests/cases/compiler/constDeclarations-ambient-errors.ts (6 errors) ====
// error: no intialization expected in ambient declarations
declare const c1: boolean = true;
@@ -17,8 +16,8 @@ tests/cases/compiler/constDeclarations-ambient-errors.ts(9,22): error TS1039: In
~
!!! error TS1039: Initializers are not allowed in ambient contexts.
declare const c3 = null, c4 :string = "", c5: any = 0;
~
!!! error TS1039: Initializers are not allowed in ambient contexts.
~~~~
!!! error TS1254: A 'const' initializer in an ambient context must be a string or numeric literal.
~
!!! error TS1039: Initializers are not allowed in ambient contexts.
~
@@ -26,8 +25,6 @@ tests/cases/compiler/constDeclarations-ambient-errors.ts(9,22): error TS1039: In
declare module M {
const c6 = 0;
~
!!! error TS1039: Initializers are not allowed in ambient contexts.
const c7: number = 7;
~
!!! error TS1039: Initializers are not allowed in ambient contexts.
@@ -25,6 +25,6 @@ for (const c5 = 0, c6 = 0; c5 < c6;) {
//// [constDeclarations.d.ts]
declare const c1: false;
declare const c1: boolean;
declare const c2: number;
declare const c3: 0, c4: string, c5: any;
declare const c3 = 0, c4: string, c5: any;
@@ -20,7 +20,7 @@ var M;
//// [constDeclarations2.d.ts]
declare module M {
const c1: false;
const c1: boolean;
const c2: number;
const c3: 0, c4: string, c5: any;
const c3 = 0, c4: string, c5: any;
}
@@ -25,7 +25,7 @@ var y = [() => new c()];
var k: (() => c) | string = (() => new c()) || "";
>k : string | (() => c)
>c : c
>(() => new c()) || "" : "" | (() => c)
>(() => new c()) || "" : (() => c) | ""
>(() => new c()) : () => c
>() => new c() : () => c
>new c() : c
@@ -45,7 +45,7 @@ var Foo = (function () {
//// [declarationEmitClassMemberNameConflict2.d.ts]
declare const Bar: "bar";
declare const Bar = "bar";
declare enum Hello {
World = 0,
}
@@ -4,7 +4,7 @@
// it is an error if there is no single BCT, these are error cases
function f1() {
>f1 : () => "" | 1
>f1 : () => 1 | ""
if (true) {
>true : true
@@ -19,7 +19,7 @@ function f1() {
}
function f2() {
>f2 : () => "" | 1 | 2
>f2 : () => 1 | "" | 2
if (true) {
>true : true
@@ -40,7 +40,7 @@ function f2() {
}
function f3() {
>f3 : () => "" | 1
>f3 : () => 1 | ""
try {
return 1;
@@ -55,7 +55,7 @@ function f3() {
}
function f4() {
>f4 : () => "" | 1
>f4 : () => 1 | ""
try {
return 1;
@@ -72,7 +72,7 @@ function f4() {
}
function f5() {
>f5 : () => "" | 1
>f5 : () => 1 | ""
return 1;
>1 : 1
@@ -0,0 +1,174 @@
//// [literalTypeWidening.ts]
// Widening vs. non-widening literal types
function f1() {
const c1 = "hello"; // Widening type "hello"
let v1 = c1; // Type string
const c2 = c1; // Widening type "hello"
let v2 = c2; // Type string
const c3: "hello" = "hello"; // Type "hello"
let v3 = c3; // Type "hello"
const c4: "hello" = c1; // Type "hello"
let v4 = c4; // Type "hello"
}
function f2(cond: boolean) {
const c1 = cond ? "foo" : "bar"; // widening "foo" | widening "bar"
const c2: "foo" | "bar" = c1; // "foo" | "bar"
const c3 = cond ? c1 : c2; // "foo" | "bar"
const c4 = cond ? c3 : "baz"; // "foo" | "bar" | widening "baz"
const c5: "foo" | "bar" | "baz" = c4; // "foo" | "bar" | "baz"
let v1 = c1; // string
let v2 = c2; // "foo" | "bar"
let v3 = c3; // "foo" | "bar"
let v4 = c4; // string
let v5 = c5; // "foo" | "bar" | "baz"
}
function f3() {
const c1 = 123; // Widening type 123
let v1 = c1; // Type number
const c2 = c1; // Widening type 123
let v2 = c2; // Type number
const c3: 123 = 123; // Type 123
let v3 = c3; // Type 123
const c4: 123 = c1; // Type 123
let v4 = c4; // Type 123
}
function f4(cond: boolean) {
const c1 = cond ? 123 : 456; // widening 123 | widening 456
const c2: 123 | 456 = c1; // 123 | 456
const c3 = cond ? c1 : c2; // 123 | 456
const c4 = cond ? c3 : 789; // 123 | 456 | widening 789
const c5: 123 | 456 | 789 = c4; // 123 | 456 | 789
let v1 = c1; // number
let v2 = c2; // 123 | 456
let v3 = c3; // 123 | 456
let v4 = c4; // number
let v5 = c5; // 123 | 456 | 789
}
function f5() {
const c1 = "foo";
let v1 = c1;
const c2: "foo" = "foo";
let v2 = c2;
const c3 = "foo" as "foo";
let v3 = c3;
const c4 = <"foo">"foo";
let v4 = c4;
}
// Repro from #10898
type FAILURE = "FAILURE";
const FAILURE = "FAILURE";
type Result<T> = T | FAILURE;
function doWork<T>(): Result<T> {
return FAILURE;
}
function isSuccess<T>(result: Result<T>): result is T {
return !isFailure(result);
}
function isFailure<T>(result: Result<T>): result is FAILURE {
return result === FAILURE;
}
function increment(x: number): number {
return x + 1;
}
let result = doWork<number>();
if (isSuccess(result)) {
increment(result);
}
// Repro from #10898
type TestEvent = "onmouseover" | "onmouseout";
function onMouseOver(): TestEvent { return "onmouseover"; }
let x = onMouseOver();
//// [literalTypeWidening.js]
// Widening vs. non-widening literal types
function f1() {
var c1 = "hello"; // Widening type "hello"
var v1 = c1; // Type string
var c2 = c1; // Widening type "hello"
var v2 = c2; // Type string
var c3 = "hello"; // Type "hello"
var v3 = c3; // Type "hello"
var c4 = c1; // Type "hello"
var v4 = c4; // Type "hello"
}
function f2(cond) {
var c1 = cond ? "foo" : "bar"; // widening "foo" | widening "bar"
var c2 = c1; // "foo" | "bar"
var c3 = cond ? c1 : c2; // "foo" | "bar"
var c4 = cond ? c3 : "baz"; // "foo" | "bar" | widening "baz"
var c5 = c4; // "foo" | "bar" | "baz"
var v1 = c1; // string
var v2 = c2; // "foo" | "bar"
var v3 = c3; // "foo" | "bar"
var v4 = c4; // string
var v5 = c5; // "foo" | "bar" | "baz"
}
function f3() {
var c1 = 123; // Widening type 123
var v1 = c1; // Type number
var c2 = c1; // Widening type 123
var v2 = c2; // Type number
var c3 = 123; // Type 123
var v3 = c3; // Type 123
var c4 = c1; // Type 123
var v4 = c4; // Type 123
}
function f4(cond) {
var c1 = cond ? 123 : 456; // widening 123 | widening 456
var c2 = c1; // 123 | 456
var c3 = cond ? c1 : c2; // 123 | 456
var c4 = cond ? c3 : 789; // 123 | 456 | widening 789
var c5 = c4; // 123 | 456 | 789
var v1 = c1; // number
var v2 = c2; // 123 | 456
var v3 = c3; // 123 | 456
var v4 = c4; // number
var v5 = c5; // 123 | 456 | 789
}
function f5() {
var c1 = "foo";
var v1 = c1;
var c2 = "foo";
var v2 = c2;
var c3 = "foo";
var v3 = c3;
var c4 = "foo";
var v4 = c4;
}
var FAILURE = "FAILURE";
function doWork() {
return FAILURE;
}
function isSuccess(result) {
return !isFailure(result);
}
function isFailure(result) {
return result === FAILURE;
}
function increment(x) {
return x + 1;
}
var result = doWork();
if (isSuccess(result)) {
increment(result);
}
function onMouseOver() { return "onmouseover"; }
var x = onMouseOver();
@@ -0,0 +1,285 @@
=== tests/cases/conformance/types/literal/literalTypeWidening.ts ===
// Widening vs. non-widening literal types
function f1() {
>f1 : Symbol(f1, Decl(literalTypeWidening.ts, 0, 0))
const c1 = "hello"; // Widening type "hello"
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 3, 9))
let v1 = c1; // Type string
>v1 : Symbol(v1, Decl(literalTypeWidening.ts, 4, 7))
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 3, 9))
const c2 = c1; // Widening type "hello"
>c2 : Symbol(c2, Decl(literalTypeWidening.ts, 5, 9))
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 3, 9))
let v2 = c2; // Type string
>v2 : Symbol(v2, Decl(literalTypeWidening.ts, 6, 7))
>c2 : Symbol(c2, Decl(literalTypeWidening.ts, 5, 9))
const c3: "hello" = "hello"; // Type "hello"
>c3 : Symbol(c3, Decl(literalTypeWidening.ts, 7, 9))
let v3 = c3; // Type "hello"
>v3 : Symbol(v3, Decl(literalTypeWidening.ts, 8, 7))
>c3 : Symbol(c3, Decl(literalTypeWidening.ts, 7, 9))
const c4: "hello" = c1; // Type "hello"
>c4 : Symbol(c4, Decl(literalTypeWidening.ts, 9, 9))
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 3, 9))
let v4 = c4; // Type "hello"
>v4 : Symbol(v4, Decl(literalTypeWidening.ts, 10, 7))
>c4 : Symbol(c4, Decl(literalTypeWidening.ts, 9, 9))
}
function f2(cond: boolean) {
>f2 : Symbol(f2, Decl(literalTypeWidening.ts, 11, 1))
>cond : Symbol(cond, Decl(literalTypeWidening.ts, 13, 12))
const c1 = cond ? "foo" : "bar"; // widening "foo" | widening "bar"
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 14, 9))
>cond : Symbol(cond, Decl(literalTypeWidening.ts, 13, 12))
const c2: "foo" | "bar" = c1; // "foo" | "bar"
>c2 : Symbol(c2, Decl(literalTypeWidening.ts, 15, 9))
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 14, 9))
const c3 = cond ? c1 : c2; // "foo" | "bar"
>c3 : Symbol(c3, Decl(literalTypeWidening.ts, 16, 9))
>cond : Symbol(cond, Decl(literalTypeWidening.ts, 13, 12))
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 14, 9))
>c2 : Symbol(c2, Decl(literalTypeWidening.ts, 15, 9))
const c4 = cond ? c3 : "baz"; // "foo" | "bar" | widening "baz"
>c4 : Symbol(c4, Decl(literalTypeWidening.ts, 17, 9))
>cond : Symbol(cond, Decl(literalTypeWidening.ts, 13, 12))
>c3 : Symbol(c3, Decl(literalTypeWidening.ts, 16, 9))
const c5: "foo" | "bar" | "baz" = c4; // "foo" | "bar" | "baz"
>c5 : Symbol(c5, Decl(literalTypeWidening.ts, 18, 9))
>c4 : Symbol(c4, Decl(literalTypeWidening.ts, 17, 9))
let v1 = c1; // string
>v1 : Symbol(v1, Decl(literalTypeWidening.ts, 19, 7))
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 14, 9))
let v2 = c2; // "foo" | "bar"
>v2 : Symbol(v2, Decl(literalTypeWidening.ts, 20, 7))
>c2 : Symbol(c2, Decl(literalTypeWidening.ts, 15, 9))
let v3 = c3; // "foo" | "bar"
>v3 : Symbol(v3, Decl(literalTypeWidening.ts, 21, 7))
>c3 : Symbol(c3, Decl(literalTypeWidening.ts, 16, 9))
let v4 = c4; // string
>v4 : Symbol(v4, Decl(literalTypeWidening.ts, 22, 7))
>c4 : Symbol(c4, Decl(literalTypeWidening.ts, 17, 9))
let v5 = c5; // "foo" | "bar" | "baz"
>v5 : Symbol(v5, Decl(literalTypeWidening.ts, 23, 7))
>c5 : Symbol(c5, Decl(literalTypeWidening.ts, 18, 9))
}
function f3() {
>f3 : Symbol(f3, Decl(literalTypeWidening.ts, 24, 1))
const c1 = 123; // Widening type 123
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 27, 9))
let v1 = c1; // Type number
>v1 : Symbol(v1, Decl(literalTypeWidening.ts, 28, 7))
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 27, 9))
const c2 = c1; // Widening type 123
>c2 : Symbol(c2, Decl(literalTypeWidening.ts, 29, 9))
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 27, 9))
let v2 = c2; // Type number
>v2 : Symbol(v2, Decl(literalTypeWidening.ts, 30, 7))
>c2 : Symbol(c2, Decl(literalTypeWidening.ts, 29, 9))
const c3: 123 = 123; // Type 123
>c3 : Symbol(c3, Decl(literalTypeWidening.ts, 31, 9))
let v3 = c3; // Type 123
>v3 : Symbol(v3, Decl(literalTypeWidening.ts, 32, 7))
>c3 : Symbol(c3, Decl(literalTypeWidening.ts, 31, 9))
const c4: 123 = c1; // Type 123
>c4 : Symbol(c4, Decl(literalTypeWidening.ts, 33, 9))
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 27, 9))
let v4 = c4; // Type 123
>v4 : Symbol(v4, Decl(literalTypeWidening.ts, 34, 7))
>c4 : Symbol(c4, Decl(literalTypeWidening.ts, 33, 9))
}
function f4(cond: boolean) {
>f4 : Symbol(f4, Decl(literalTypeWidening.ts, 35, 1))
>cond : Symbol(cond, Decl(literalTypeWidening.ts, 37, 12))
const c1 = cond ? 123 : 456; // widening 123 | widening 456
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 38, 9))
>cond : Symbol(cond, Decl(literalTypeWidening.ts, 37, 12))
const c2: 123 | 456 = c1; // 123 | 456
>c2 : Symbol(c2, Decl(literalTypeWidening.ts, 39, 9))
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 38, 9))
const c3 = cond ? c1 : c2; // 123 | 456
>c3 : Symbol(c3, Decl(literalTypeWidening.ts, 40, 9))
>cond : Symbol(cond, Decl(literalTypeWidening.ts, 37, 12))
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 38, 9))
>c2 : Symbol(c2, Decl(literalTypeWidening.ts, 39, 9))
const c4 = cond ? c3 : 789; // 123 | 456 | widening 789
>c4 : Symbol(c4, Decl(literalTypeWidening.ts, 41, 9))
>cond : Symbol(cond, Decl(literalTypeWidening.ts, 37, 12))
>c3 : Symbol(c3, Decl(literalTypeWidening.ts, 40, 9))
const c5: 123 | 456 | 789 = c4; // 123 | 456 | 789
>c5 : Symbol(c5, Decl(literalTypeWidening.ts, 42, 9))
>c4 : Symbol(c4, Decl(literalTypeWidening.ts, 41, 9))
let v1 = c1; // number
>v1 : Symbol(v1, Decl(literalTypeWidening.ts, 43, 7))
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 38, 9))
let v2 = c2; // 123 | 456
>v2 : Symbol(v2, Decl(literalTypeWidening.ts, 44, 7))
>c2 : Symbol(c2, Decl(literalTypeWidening.ts, 39, 9))
let v3 = c3; // 123 | 456
>v3 : Symbol(v3, Decl(literalTypeWidening.ts, 45, 7))
>c3 : Symbol(c3, Decl(literalTypeWidening.ts, 40, 9))
let v4 = c4; // number
>v4 : Symbol(v4, Decl(literalTypeWidening.ts, 46, 7))
>c4 : Symbol(c4, Decl(literalTypeWidening.ts, 41, 9))
let v5 = c5; // 123 | 456 | 789
>v5 : Symbol(v5, Decl(literalTypeWidening.ts, 47, 7))
>c5 : Symbol(c5, Decl(literalTypeWidening.ts, 42, 9))
}
function f5() {
>f5 : Symbol(f5, Decl(literalTypeWidening.ts, 48, 1))
const c1 = "foo";
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 51, 9))
let v1 = c1;
>v1 : Symbol(v1, Decl(literalTypeWidening.ts, 52, 7))
>c1 : Symbol(c1, Decl(literalTypeWidening.ts, 51, 9))
const c2: "foo" = "foo";
>c2 : Symbol(c2, Decl(literalTypeWidening.ts, 53, 9))
let v2 = c2;
>v2 : Symbol(v2, Decl(literalTypeWidening.ts, 54, 7))
>c2 : Symbol(c2, Decl(literalTypeWidening.ts, 53, 9))
const c3 = "foo" as "foo";
>c3 : Symbol(c3, Decl(literalTypeWidening.ts, 55, 9))
let v3 = c3;
>v3 : Symbol(v3, Decl(literalTypeWidening.ts, 56, 7))
>c3 : Symbol(c3, Decl(literalTypeWidening.ts, 55, 9))
const c4 = <"foo">"foo";
>c4 : Symbol(c4, Decl(literalTypeWidening.ts, 57, 9))
let v4 = c4;
>v4 : Symbol(v4, Decl(literalTypeWidening.ts, 58, 7))
>c4 : Symbol(c4, Decl(literalTypeWidening.ts, 57, 9))
}
// Repro from #10898
type FAILURE = "FAILURE";
>FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 59, 1), Decl(literalTypeWidening.ts, 64, 5))
const FAILURE = "FAILURE";
>FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 59, 1), Decl(literalTypeWidening.ts, 64, 5))
type Result<T> = T | FAILURE;
>Result : Symbol(Result, Decl(literalTypeWidening.ts, 64, 26))
>T : Symbol(T, Decl(literalTypeWidening.ts, 66, 12))
>T : Symbol(T, Decl(literalTypeWidening.ts, 66, 12))
>FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 59, 1), Decl(literalTypeWidening.ts, 64, 5))
function doWork<T>(): Result<T> {
>doWork : Symbol(doWork, Decl(literalTypeWidening.ts, 66, 29))
>T : Symbol(T, Decl(literalTypeWidening.ts, 68, 16))
>Result : Symbol(Result, Decl(literalTypeWidening.ts, 64, 26))
>T : Symbol(T, Decl(literalTypeWidening.ts, 68, 16))
return FAILURE;
>FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 59, 1), Decl(literalTypeWidening.ts, 64, 5))
}
function isSuccess<T>(result: Result<T>): result is T {
>isSuccess : Symbol(isSuccess, Decl(literalTypeWidening.ts, 70, 1))
>T : Symbol(T, Decl(literalTypeWidening.ts, 72, 19))
>result : Symbol(result, Decl(literalTypeWidening.ts, 72, 22))
>Result : Symbol(Result, Decl(literalTypeWidening.ts, 64, 26))
>T : Symbol(T, Decl(literalTypeWidening.ts, 72, 19))
>result : Symbol(result, Decl(literalTypeWidening.ts, 72, 22))
>T : Symbol(T, Decl(literalTypeWidening.ts, 72, 19))
return !isFailure(result);
>isFailure : Symbol(isFailure, Decl(literalTypeWidening.ts, 74, 1))
>result : Symbol(result, Decl(literalTypeWidening.ts, 72, 22))
}
function isFailure<T>(result: Result<T>): result is FAILURE {
>isFailure : Symbol(isFailure, Decl(literalTypeWidening.ts, 74, 1))
>T : Symbol(T, Decl(literalTypeWidening.ts, 76, 19))
>result : Symbol(result, Decl(literalTypeWidening.ts, 76, 22))
>Result : Symbol(Result, Decl(literalTypeWidening.ts, 64, 26))
>T : Symbol(T, Decl(literalTypeWidening.ts, 76, 19))
>result : Symbol(result, Decl(literalTypeWidening.ts, 76, 22))
>FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 59, 1), Decl(literalTypeWidening.ts, 64, 5))
return result === FAILURE;
>result : Symbol(result, Decl(literalTypeWidening.ts, 76, 22))
>FAILURE : Symbol(FAILURE, Decl(literalTypeWidening.ts, 59, 1), Decl(literalTypeWidening.ts, 64, 5))
}
function increment(x: number): number {
>increment : Symbol(increment, Decl(literalTypeWidening.ts, 78, 1))
>x : Symbol(x, Decl(literalTypeWidening.ts, 80, 19))
return x + 1;
>x : Symbol(x, Decl(literalTypeWidening.ts, 80, 19))
}
let result = doWork<number>();
>result : Symbol(result, Decl(literalTypeWidening.ts, 84, 3))
>doWork : Symbol(doWork, Decl(literalTypeWidening.ts, 66, 29))
if (isSuccess(result)) {
>isSuccess : Symbol(isSuccess, Decl(literalTypeWidening.ts, 70, 1))
>result : Symbol(result, Decl(literalTypeWidening.ts, 84, 3))
increment(result);
>increment : Symbol(increment, Decl(literalTypeWidening.ts, 78, 1))
>result : Symbol(result, Decl(literalTypeWidening.ts, 84, 3))
}
// Repro from #10898
type TestEvent = "onmouseover" | "onmouseout";
>TestEvent : Symbol(TestEvent, Decl(literalTypeWidening.ts, 88, 1))
function onMouseOver(): TestEvent { return "onmouseover"; }
>onMouseOver : Symbol(onMouseOver, Decl(literalTypeWidening.ts, 92, 46))
>TestEvent : Symbol(TestEvent, Decl(literalTypeWidening.ts, 88, 1))
let x = onMouseOver();
>x : Symbol(x, Decl(literalTypeWidening.ts, 96, 3))
>onMouseOver : Symbol(onMouseOver, Decl(literalTypeWidening.ts, 92, 46))
@@ -0,0 +1,318 @@
=== tests/cases/conformance/types/literal/literalTypeWidening.ts ===
// Widening vs. non-widening literal types
function f1() {
>f1 : () => void
const c1 = "hello"; // Widening type "hello"
>c1 : "hello"
>"hello" : "hello"
let v1 = c1; // Type string
>v1 : string
>c1 : "hello"
const c2 = c1; // Widening type "hello"
>c2 : "hello"
>c1 : "hello"
let v2 = c2; // Type string
>v2 : string
>c2 : "hello"
const c3: "hello" = "hello"; // Type "hello"
>c3 : "hello"
>"hello" : "hello"
let v3 = c3; // Type "hello"
>v3 : "hello"
>c3 : "hello"
const c4: "hello" = c1; // Type "hello"
>c4 : "hello"
>c1 : "hello"
let v4 = c4; // Type "hello"
>v4 : "hello"
>c4 : "hello"
}
function f2(cond: boolean) {
>f2 : (cond: boolean) => void
>cond : boolean
const c1 = cond ? "foo" : "bar"; // widening "foo" | widening "bar"
>c1 : "foo" | "bar"
>cond ? "foo" : "bar" : "foo" | "bar"
>cond : boolean
>"foo" : "foo"
>"bar" : "bar"
const c2: "foo" | "bar" = c1; // "foo" | "bar"
>c2 : "foo" | "bar"
>c1 : "foo" | "bar"
const c3 = cond ? c1 : c2; // "foo" | "bar"
>c3 : "foo" | "bar"
>cond ? c1 : c2 : "foo" | "bar"
>cond : boolean
>c1 : "foo" | "bar"
>c2 : "foo" | "bar"
const c4 = cond ? c3 : "baz"; // "foo" | "bar" | widening "baz"
>c4 : "foo" | "bar" | "baz"
>cond ? c3 : "baz" : "foo" | "bar" | "baz"
>cond : boolean
>c3 : "foo" | "bar"
>"baz" : "baz"
const c5: "foo" | "bar" | "baz" = c4; // "foo" | "bar" | "baz"
>c5 : "foo" | "bar" | "baz"
>c4 : "foo" | "bar" | "baz"
let v1 = c1; // string
>v1 : string
>c1 : "foo" | "bar"
let v2 = c2; // "foo" | "bar"
>v2 : "foo" | "bar"
>c2 : "foo" | "bar"
let v3 = c3; // "foo" | "bar"
>v3 : "foo" | "bar"
>c3 : "foo" | "bar"
let v4 = c4; // string
>v4 : string
>c4 : "foo" | "bar" | "baz"
let v5 = c5; // "foo" | "bar" | "baz"
>v5 : "foo" | "bar" | "baz"
>c5 : "foo" | "bar" | "baz"
}
function f3() {
>f3 : () => void
const c1 = 123; // Widening type 123
>c1 : 123
>123 : 123
let v1 = c1; // Type number
>v1 : number
>c1 : 123
const c2 = c1; // Widening type 123
>c2 : 123
>c1 : 123
let v2 = c2; // Type number
>v2 : number
>c2 : 123
const c3: 123 = 123; // Type 123
>c3 : 123
>123 : 123
let v3 = c3; // Type 123
>v3 : 123
>c3 : 123
const c4: 123 = c1; // Type 123
>c4 : 123
>c1 : 123
let v4 = c4; // Type 123
>v4 : 123
>c4 : 123
}
function f4(cond: boolean) {
>f4 : (cond: boolean) => void
>cond : boolean
const c1 = cond ? 123 : 456; // widening 123 | widening 456
>c1 : 123 | 456
>cond ? 123 : 456 : 123 | 456
>cond : boolean
>123 : 123
>456 : 456
const c2: 123 | 456 = c1; // 123 | 456
>c2 : 123 | 456
>c1 : 123 | 456
const c3 = cond ? c1 : c2; // 123 | 456
>c3 : 123 | 456
>cond ? c1 : c2 : 123 | 456
>cond : boolean
>c1 : 123 | 456
>c2 : 123 | 456
const c4 = cond ? c3 : 789; // 123 | 456 | widening 789
>c4 : 123 | 456 | 789
>cond ? c3 : 789 : 123 | 456 | 789
>cond : boolean
>c3 : 123 | 456
>789 : 789
const c5: 123 | 456 | 789 = c4; // 123 | 456 | 789
>c5 : 123 | 456 | 789
>c4 : 123 | 456 | 789
let v1 = c1; // number
>v1 : number
>c1 : 123 | 456
let v2 = c2; // 123 | 456
>v2 : 123 | 456
>c2 : 123 | 456
let v3 = c3; // 123 | 456
>v3 : 123 | 456
>c3 : 123 | 456
let v4 = c4; // number
>v4 : number
>c4 : 123 | 456 | 789
let v5 = c5; // 123 | 456 | 789
>v5 : 123 | 456 | 789
>c5 : 123 | 456 | 789
}
function f5() {
>f5 : () => void
const c1 = "foo";
>c1 : "foo"
>"foo" : "foo"
let v1 = c1;
>v1 : string
>c1 : "foo"
const c2: "foo" = "foo";
>c2 : "foo"
>"foo" : "foo"
let v2 = c2;
>v2 : "foo"
>c2 : "foo"
const c3 = "foo" as "foo";
>c3 : "foo"
>"foo" as "foo" : "foo"
>"foo" : "foo"
let v3 = c3;
>v3 : "foo"
>c3 : "foo"
const c4 = <"foo">"foo";
>c4 : "foo"
><"foo">"foo" : "foo"
>"foo" : "foo"
let v4 = c4;
>v4 : "foo"
>c4 : "foo"
}
// Repro from #10898
type FAILURE = "FAILURE";
>FAILURE : "FAILURE"
const FAILURE = "FAILURE";
>FAILURE : "FAILURE"
>"FAILURE" : "FAILURE"
type Result<T> = T | FAILURE;
>Result : Result<T>
>T : T
>T : T
>FAILURE : "FAILURE"
function doWork<T>(): Result<T> {
>doWork : <T>() => Result<T>
>T : T
>Result : Result<T>
>T : T
return FAILURE;
>FAILURE : "FAILURE"
}
function isSuccess<T>(result: Result<T>): result is T {
>isSuccess : <T>(result: Result<T>) => result is T
>T : T
>result : Result<T>
>Result : Result<T>
>T : T
>result : any
>T : T
return !isFailure(result);
>!isFailure(result) : boolean
>isFailure(result) : boolean
>isFailure : <T>(result: Result<T>) => result is "FAILURE"
>result : Result<T>
}
function isFailure<T>(result: Result<T>): result is FAILURE {
>isFailure : <T>(result: Result<T>) => result is "FAILURE"
>T : T
>result : Result<T>
>Result : Result<T>
>T : T
>result : any
>FAILURE : "FAILURE"
return result === FAILURE;
>result === FAILURE : boolean
>result : Result<T>
>FAILURE : "FAILURE"
}
function increment(x: number): number {
>increment : (x: number) => number
>x : number
return x + 1;
>x + 1 : number
>x : number
>1 : 1
}
let result = doWork<number>();
>result : Result<number>
>doWork<number>() : Result<number>
>doWork : <T>() => Result<T>
if (isSuccess(result)) {
>isSuccess(result) : boolean
>isSuccess : <T>(result: Result<T>) => result is T
>result : Result<number>
increment(result);
>increment(result) : number
>increment : (x: number) => number
>result : number
}
// Repro from #10898
type TestEvent = "onmouseover" | "onmouseout";
>TestEvent : TestEvent
function onMouseOver(): TestEvent { return "onmouseover"; }
>onMouseOver : () => TestEvent
>TestEvent : TestEvent
>"onmouseover" : "onmouseover"
let x = onMouseOver();
>x : TestEvent
>onMouseOver() : TestEvent
>onMouseOver : () => TestEvent
@@ -482,7 +482,7 @@ function f6() {
const { c1 = true, c2 = 0, c3 = "foo" } = { c1: false, c2: 1, c3: "bar" };
>c1 : boolean
>true : true
>c2 : 0 | 1
>c2 : 1 | 0
>0 : 0
>c3 : "foo" | "bar"
>"foo" : "foo"
@@ -552,10 +552,10 @@ class C2 {
>0 : 0
}
bar() {
>bar : () => 0 | 1
>bar : () => 1 | 0
return cond ? 0 : 1;
>cond ? 0 : 1 : 0 | 1
>cond ? 0 : 1 : 1 | 0
>cond : boolean
>0 : 0
>1 : 1
@@ -370,7 +370,7 @@ function f14(x: 0 | 1 | 2, y: string) {
>y : string
var b = x || y;
>b : string | number
>b : string | 1 | 2
>x || y : string | 1 | 2
>x : 0 | 1 | 2
>y : string
@@ -383,25 +383,25 @@ function f15(x: 0 | false, y: 1 | "one") {
>y : 1 | "one"
var a = x && y;
>a : number | boolean
>a : boolean | 0
>x && y : false | 0
>x : false | 0
>y : 1 | "one"
var b = y && x;
>b : number | boolean
>b : boolean | 0
>y && x : false | 0
>y : 1 | "one"
>x : false | 0
var c = x || y;
>c : string | number
>c : 1 | "one"
>x || y : 1 | "one"
>x : false | 0
>y : 1 | "one"
var d = y || x;
>d : string | number | boolean
>d : boolean | 0 | 1 | "one"
>y || x : false | 0 | 1 | "one"
>y : 1 | "one"
>x : false | 0
@@ -365,13 +365,13 @@ function f14(x: 0 | 1 | 2, y: string) {
>y : string
var a = x && y;
>a : string | number
>a : string | 0
>x && y : string | 0
>x : 0 | 1 | 2
>y : string
var b = x || y;
>b : string | number
>b : string | 1 | 2
>x || y : string | 1 | 2
>x : 0 | 1 | 2
>y : string
@@ -384,25 +384,25 @@ function f15(x: 0 | false, y: 1 | "one") {
>y : 1 | "one"
var a = x && y;
>a : number | boolean
>a : boolean | 0
>x && y : false | 0
>x : false | 0
>y : 1 | "one"
var b = y && x;
>b : number | boolean
>b : boolean | 0
>y && x : false | 0
>y : 1 | "one"
>x : false | 0
var c = x || y;
>c : string | number
>c : 1 | "one"
>x || y : 1 | "one"
>x : false | 0
>y : 1 | "one"
var d = y || x;
>d : string | number
>d : 1 | "one"
>y || x : 1 | "one"
>y : 1 | "one"
>x : false | 0
@@ -17,5 +17,5 @@ exports.foo = foo;
//// [shorthandOfExportedEntity01_targetES2015_CommonJS.d.ts]
export declare const test: "test";
export declare const test = "test";
export declare function foo(): void;
@@ -17,5 +17,5 @@ exports.foo = foo;
//// [shorthandOfExportedEntity02_targetES5_CommonJS.d.ts]
export declare const test: "test";
export declare const test = "test";
export declare function foo(): void;
@@ -1,16 +1,13 @@
tests/cases/conformance/types/stringLiteral/stringLiteralTypesAndLogicalOrExpressions01.ts(6,5): error TS2322: Type 'string' is not assignable to type '"foo"'.
tests/cases/conformance/types/stringLiteral/stringLiteralTypesAndLogicalOrExpressions01.ts(8,5): error TS2322: Type 'string' is not assignable to type '"foo" | "bar"'.
==== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAndLogicalOrExpressions01.ts (2 errors) ====
==== tests/cases/conformance/types/stringLiteral/stringLiteralTypesAndLogicalOrExpressions01.ts (1 errors) ====
declare function myRandBool(): boolean;
let a: "foo" = "foo";
let b = a || "foo";
let c: "foo" = b;
~
!!! error TS2322: Type 'string' is not assignable to type '"foo"'.
let d = b || "bar";
let e: "foo" | "bar" = d;
~
@@ -20,7 +20,7 @@ var e = d;
//// [stringLiteralTypesAndLogicalOrExpressions01.d.ts]
declare function myRandBool(): boolean;
declare let a: "foo";
declare let b: string;
declare let b: "foo";
declare let c: "foo";
declare let d: string;
declare let e: "foo" | "bar";
@@ -38,8 +38,8 @@ hResult = h("bar");
declare function foo<T extends "foo">(f: (x: T) => T): (x: T) => T;
declare function bar<T extends "foo" | "bar">(f: (x: T) => T): (x: T) => T;
declare let f: (x: "foo") => "foo";
declare let fResult: string;
declare let fResult: "foo";
declare let g: (x: "foo") => "foo";
declare let gResult: string;
declare let gResult: "foo";
declare let h: (x: "foo" | "bar") => "foo" | "bar";
declare let hResult: string;
declare let hResult: "foo" | "bar";
@@ -33,7 +33,7 @@ let f = foo(x => x);
>x : "foo"
let fResult = f("foo");
>fResult : string
>fResult : "foo"
>f("foo") : "foo"
>f : (x: "foo") => "foo"
>"foo" : "foo"
@@ -48,7 +48,7 @@ let g = foo((x => x));
>x : "foo"
let gResult = g("foo");
>gResult : string
>gResult : "foo"
>g("foo") : "foo"
>g : (x: "foo") => "foo"
>"foo" : "foo"
@@ -62,14 +62,14 @@ let h = bar(x => x);
>x : "foo" | "bar"
let hResult = h("foo");
>hResult : string
>hResult : "foo" | "bar"
>h("foo") : "foo" | "bar"
>h : (x: "foo" | "bar") => "foo" | "bar"
>"foo" : "foo"
hResult = h("bar");
>hResult = h("bar") : "foo" | "bar"
>hResult : string
>hResult : "foo" | "bar"
>h("bar") : "foo" | "bar"
>h : (x: "foo" | "bar") => "foo" | "bar"
>"bar" : "bar"
@@ -18,4 +18,4 @@ var fResult = f("foo");
//// [stringLiteralTypesAsTypeParameterConstraint02.d.ts]
declare function foo<T extends "foo">(f: (x: T) => T): (x: T) => T;
declare let f: (x: "foo") => "foo";
declare let fResult: string;
declare let fResult: "foo";
@@ -26,7 +26,7 @@ let f = foo((y: "foo" | "bar") => y === "foo" ? y : "foo");
>"foo" : "foo"
let fResult = f("foo");
>fResult : string
>fResult : "foo"
>f("foo") : "foo"
>f : (x: "foo") => "foo"
>"foo" : "foo"
@@ -1,26 +0,0 @@
tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes01.ts(16,9): error TS2322: Type 'string' is not assignable to type '"foo" | "bar" | "baz"'.
==== tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes01.ts (1 errors) ====
type T = "foo" | "bar" | "baz";
var x: "foo" | "bar" | "baz" = undefined;
var y: T = undefined;
if (x === "foo") {
let a = x;
}
else if (x !== "bar") {
let b = x || y;
}
else {
let c = x;
let d = y;
let e: (typeof x) | (typeof y) = c || d;
~
!!! error TS2322: Type 'string' is not assignable to type '"foo" | "bar" | "baz"'.
}
x = y;
y = x;
@@ -1,62 +1,62 @@
=== tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes02.ts ===
type T = string | "foo" | "bar" | "baz";
>T : string | "foo" | "bar" | "baz"
>T : string
var x: "foo" | "bar" | "baz" | string = undefined;
>x : string | "foo" | "bar" | "baz"
>x : string
>undefined : undefined
var y: T = undefined;
>y : string | "foo" | "bar" | "baz"
>T : string | "foo" | "bar" | "baz"
>y : string
>T : string
>undefined : undefined
if (x === "foo") {
>x === "foo" : boolean
>x : string | "foo" | "bar" | "baz"
>x : string
>"foo" : "foo"
let a = x;
>a : string
>x : string | "foo"
>x : string
}
else if (x !== "bar") {
>x !== "bar" : boolean
>x : string | "bar" | "baz"
>x : string
>"bar" : "bar"
let b = x || y;
>b : string
>x || y : string
>x : string | "baz"
>y : string | "foo" | "bar" | "baz"
>x : string
>y : string
}
else {
let c = x;
>c : string
>x : string | "bar"
>x : string
let d = y;
>d : string
>y : string | "foo" | "bar" | "baz"
>y : string
let e: (typeof x) | (typeof y) = c || d;
>e : string | "foo" | "bar" | "baz"
>x : string | "bar"
>y : string | "foo" | "bar" | "baz"
>e : string
>x : string
>y : string
>c || d : string
>c : string
>d : string
}
x = y;
>x = y : string | "foo" | "bar" | "baz"
>x : string | "foo" | "bar" | "baz"
>y : string | "foo" | "bar" | "baz"
>x = y : string
>x : string
>y : string
y = x;
>y = x : string | "foo" | "bar" | "baz"
>y : string | "foo" | "bar" | "baz"
>x : string | "foo" | "bar" | "baz"
>y = x : string
>y : string
>x : string
@@ -1,28 +0,0 @@
tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes03.ts(16,9): error TS2322: Type 'string | number' is not assignable to type 'number | "foo" | "bar"'.
Type 'string' is not assignable to type 'number | "foo" | "bar"'.
==== tests/cases/conformance/types/stringLiteral/stringLiteralTypesInUnionTypes03.ts (1 errors) ====
type T = number | "foo" | "bar";
var x: "foo" | "bar" | number;
var y: T = undefined;
if (x === "foo") {
let a = x;
}
else if (x !== "bar") {
let b = x || y;
}
else {
let c = x;
let d = y;
let e: (typeof x) | (typeof y) = c || d;
~
!!! error TS2322: Type 'string | number' is not assignable to type 'number | "foo" | "bar"'.
!!! error TS2322: Type 'string' is not assignable to type 'number | "foo" | "bar"'.
}
x = y;
y = x;
@@ -19,7 +19,7 @@ if (x === "") {
>"" : ""
let a = x;
>a : string
>a : ""
>x : ""
}
@@ -29,7 +29,7 @@ if (x !== "") {
>"" : ""
let b = x;
>b : string
>b : "foo"
>x : "foo"
}
@@ -39,7 +39,7 @@ if (x == "") {
>"" : ""
let c = x;
>c : string
>c : ""
>x : ""
}
@@ -49,7 +49,7 @@ if (x != "") {
>"" : ""
let d = x;
>d : string
>d : "foo"
>x : "foo"
}
@@ -57,7 +57,7 @@ if (x) {
>x : T
let e = x;
>e : string
>e : "foo"
>x : "foo"
}
@@ -66,7 +66,7 @@ if (!x) {
>x : T
let f = x;
>f : string
>f : T
>x : T
}
@@ -76,7 +76,7 @@ if (!!x) {
>x : T
let g = x;
>g : string
>g : "foo"
>x : "foo"
}
@@ -87,6 +87,6 @@ if (!!!x) {
>x : T
let h = x;
>h : string
>h : T
>x : T
}
@@ -100,12 +100,12 @@ declare function getFalsyPrimitive(x: "number" | "string"): number | string;
declare function getFalsyPrimitive(x: "number" | "string" | "boolean"): number | string | boolean;
declare namespace Consts1 {
}
declare const string: "string";
declare const number: "number";
declare const boolean: "boolean";
declare const stringOrNumber: "string" | "number";
declare const stringOrBoolean: "string" | "boolean";
declare const booleanOrNumber: "number" | "boolean";
declare const stringOrBooleanOrNumber: "string" | "number" | "boolean";
declare const string = "string";
declare const number = "number";
declare const boolean = "boolean";
declare const stringOrNumber: string;
declare const stringOrBoolean: string;
declare const booleanOrNumber: string;
declare const stringOrBooleanOrNumber: string;
declare namespace Consts2 {
}
@@ -42,12 +42,12 @@ if (kindIs(x, "A")) {
>"A" : "A"
let a = x;
>a : string
>a : "A"
>x : "A"
}
else {
let b = x;
>b : string
>b : "B"
>x : "B"
}
@@ -59,11 +59,11 @@ if (!kindIs(x, "B")) {
>"B" : "B"
let c = x;
>c : string
>c : "A"
>x : "A"
}
else {
let d = x;
>d : string
>d : "B"
>x : "B"
}
@@ -259,14 +259,14 @@ function f6<T extends String>(x: T) {
var r2 = true ? '' : x; // ok
>r2 : string | T
>true ? '' : x : "" | T
>true ? '' : x : T | ""
>true : true
>'' : ""
>x : T
var r2 = true ? x : ''; // ok
>r2 : string | T
>true ? x : '' : "" | T
>true ? x : '' : T | ""
>true : true
>x : T
>'' : ""
@@ -11,17 +11,21 @@ tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes0
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(55,43): error TS2345: Argument of type '"World"' is not assignable to parameter of type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(57,52): error TS2345: Argument of type '"World"' is not assignable to parameter of type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(58,43): error TS2345: Argument of type '"World"' is not assignable to parameter of type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(68,25): error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(70,25): error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(75,30): error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello" | "World"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(77,30): error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello" | "World"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(61,5): error TS2322: Type 'string' is not assignable to type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(63,5): error TS2322: Type 'string' is not assignable to type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(75,5): error TS2322: Type '"Hello" | "World"' is not assignable to type '"Hello"'.
Type '"World"' is not assignable to type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(77,5): error TS2322: Type '"Hello" | "World"' is not assignable to type '"Hello"'.
Type '"World"' is not assignable to type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(87,43): error TS2345: Argument of type '"World"' is not assignable to parameter of type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(88,43): error TS2345: Argument of type '"Hello"' is not assignable to parameter of type '"World"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(89,52): error TS2345: Argument of type '"World"' is not assignable to parameter of type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(100,25): error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(104,25): error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(107,30): error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello" | "World"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(111,30): error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello" | "World"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(93,5): error TS2322: Type 'string' is not assignable to type '"Hello" | "World"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(97,5): error TS2322: Type 'string' is not assignable to type '"Hello" | "World"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(100,25): error TS2345: Argument of type '"Hello" | "World"' is not assignable to parameter of type '"Hello"'.
Type '"World"' is not assignable to type '"Hello"'.
tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts(104,25): error TS2345: Argument of type '"Hello" | "World"' is not assignable to parameter of type '"Hello"'.
Type '"World"' is not assignable to type '"Hello"'.
==== tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes01.ts (24 errors) ====
@@ -112,30 +116,32 @@ tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes0
// Assignment from the returned value should cause an error.
a = takeReturnString(a);
~
!!! error TS2322: Type 'string' is not assignable to type '"Hello"'.
b = takeReturnString(b);
c = takeReturnString(c);
~
!!! error TS2322: Type 'string' is not assignable to type '"Hello"'.
d = takeReturnString(d);
e = takeReturnString(e);
// Should be valid
a = takeReturnHello(a);
~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello"'.
b = takeReturnHello(b);
c = takeReturnHello(c);
~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello"'.
d = takeReturnHello(d);
e = takeReturnHello(e);
// Assignment from the returned value should cause an error.
a = takeReturnHelloWorld(a);
~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello" | "World"'.
~
!!! error TS2322: Type '"Hello" | "World"' is not assignable to type '"Hello"'.
!!! error TS2322: Type '"World"' is not assignable to type '"Hello"'.
b = takeReturnHelloWorld(b);
c = takeReturnHelloWorld(c);
~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello" | "World"'.
~
!!! error TS2322: Type '"Hello" | "World"' is not assignable to type '"Hello"'.
!!! error TS2322: Type '"World"' is not assignable to type '"Hello"'.
d = takeReturnHelloWorld(d);
e = takeReturnHelloWorld(e);
}
@@ -158,30 +164,32 @@ tests/cases/conformance/types/stringLiteral/typeArgumentsWithStringLiteralTypes0
// Assignment from the returned value should cause an error.
a = takeReturnString(a);
~
!!! error TS2322: Type 'string' is not assignable to type '"Hello" | "World"'.
b = takeReturnString(b);
c = takeReturnString(c);
d = takeReturnString(d);
e = takeReturnString(e);
~
!!! error TS2322: Type 'string' is not assignable to type '"Hello" | "World"'.
// Passing these as arguments should cause an error.
a = takeReturnHello(a);
~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello"'.
!!! error TS2345: Argument of type '"Hello" | "World"' is not assignable to parameter of type '"Hello"'.
!!! error TS2345: Type '"World"' is not assignable to type '"Hello"'.
b = takeReturnHello(b);
c = takeReturnHello(c);
d = takeReturnHello(d);
e = takeReturnHello(e);
~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello"'.
!!! error TS2345: Argument of type '"Hello" | "World"' is not assignable to parameter of type '"Hello"'.
!!! error TS2345: Type '"World"' is not assignable to type '"Hello"'.
// Both should be valid.
a = takeReturnHelloWorld(a);
~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello" | "World"'.
b = takeReturnHelloWorld(b);
c = takeReturnHelloWorld(c);
d = takeReturnHelloWorld(d);
e = takeReturnHelloWorld(e);
~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type '"Hello" | "World"'.
}
@@ -229,16 +229,16 @@ declare namespace n1 {
let e: string;
}
declare namespace n2 {
let a: string;
let a: "Hello";
let b: any;
let c: string;
let c: "Hello";
let d: any;
let e: any;
}
declare namespace n3 {
let a: string;
let a: "Hello" | "World";
let b: any;
let c: any;
let d: any;
let e: string;
let e: "Hello" | "World";
}
@@ -512,7 +512,7 @@ _.compact([0, 1, false, 2, '', 3]);
>_.compact : <T>(list: T[]) => T[]
>_ : Underscore.Static
>compact : <T>(list: T[]) => T[]
>[0, 1, false, 2, '', 3] : (false | "" | 0 | 1 | 2 | 3)[]
>[0, 1, false, 2, '', 3] : (false | 1 | 2 | 3 | 0 | "")[]
>0 : 0
>1 : 1
>false : false
@@ -24,7 +24,7 @@ var species = foge[Symbol.species];
>species : symbol
var stringTag = foge[Symbol.toStringTag];
>stringTag : string
>stringTag : "SharedArrayBuffer"
>foge[Symbol.toStringTag] : "SharedArrayBuffer"
>foge : SharedArrayBuffer
>Symbol.toStringTag : symbol
@@ -15,7 +15,7 @@ var species = foge[Symbol.species];
>species : symbol
var stringTag = foge[Symbol.toStringTag];
>stringTag : string
>stringTag : "SharedArrayBuffer"
>foge[Symbol.toStringTag] : "SharedArrayBuffer"
>foge : SharedArrayBuffer
>Symbol.toStringTag : symbol
@@ -15,7 +15,7 @@ var species = foge[Symbol.species];
>species : symbol
var stringTag = foge[Symbol.toStringTag];
>stringTag : string
>stringTag : "SharedArrayBuffer"
>foge[Symbol.toStringTag] : "SharedArrayBuffer"
>foge : SharedArrayBuffer
>Symbol.toStringTag : symbol
@@ -0,0 +1,22 @@
// @declaration: true
function f<T>(x: T): T {
return x;
}
enum E { A, B, C }
const c1 = "abc";
const c2 = 123;
const c3 = c1;
const c4 = c2;
const c5 = f(123);
const c6 = f(-123);
const c7 = true;
const c8 = E.A;
const c9 = { x: "abc" };
const c10 = [123];
const c11 = "abc" + "def";
const c12 = 123 + 456;
const c13 = Math.random() > 0.5 ? "abc" : "def";
const c14 = Math.random() > 0.5 ? 123 : 456;
@@ -0,0 +1,97 @@
// Widening vs. non-widening literal types
function f1() {
const c1 = "hello"; // Widening type "hello"
let v1 = c1; // Type string
const c2 = c1; // Widening type "hello"
let v2 = c2; // Type string
const c3: "hello" = "hello"; // Type "hello"
let v3 = c3; // Type "hello"
const c4: "hello" = c1; // Type "hello"
let v4 = c4; // Type "hello"
}
function f2(cond: boolean) {
const c1 = cond ? "foo" : "bar"; // widening "foo" | widening "bar"
const c2: "foo" | "bar" = c1; // "foo" | "bar"
const c3 = cond ? c1 : c2; // "foo" | "bar"
const c4 = cond ? c3 : "baz"; // "foo" | "bar" | widening "baz"
const c5: "foo" | "bar" | "baz" = c4; // "foo" | "bar" | "baz"
let v1 = c1; // string
let v2 = c2; // "foo" | "bar"
let v3 = c3; // "foo" | "bar"
let v4 = c4; // string
let v5 = c5; // "foo" | "bar" | "baz"
}
function f3() {
const c1 = 123; // Widening type 123
let v1 = c1; // Type number
const c2 = c1; // Widening type 123
let v2 = c2; // Type number
const c3: 123 = 123; // Type 123
let v3 = c3; // Type 123
const c4: 123 = c1; // Type 123
let v4 = c4; // Type 123
}
function f4(cond: boolean) {
const c1 = cond ? 123 : 456; // widening 123 | widening 456
const c2: 123 | 456 = c1; // 123 | 456
const c3 = cond ? c1 : c2; // 123 | 456
const c4 = cond ? c3 : 789; // 123 | 456 | widening 789
const c5: 123 | 456 | 789 = c4; // 123 | 456 | 789
let v1 = c1; // number
let v2 = c2; // 123 | 456
let v3 = c3; // 123 | 456
let v4 = c4; // number
let v5 = c5; // 123 | 456 | 789
}
function f5() {
const c1 = "foo";
let v1 = c1;
const c2: "foo" = "foo";
let v2 = c2;
const c3 = "foo" as "foo";
let v3 = c3;
const c4 = <"foo">"foo";
let v4 = c4;
}
// Repro from #10898
type FAILURE = "FAILURE";
const FAILURE = "FAILURE";
type Result<T> = T | FAILURE;
function doWork<T>(): Result<T> {
return FAILURE;
}
function isSuccess<T>(result: Result<T>): result is T {
return !isFailure(result);
}
function isFailure<T>(result: Result<T>): result is FAILURE {
return result === FAILURE;
}
function increment(x: number): number {
return x + 1;
}
let result = doWork<number>();
if (isSuccess(result)) {
increment(result);
}
// Repro from #10898
type TestEvent = "onmouseover" | "onmouseout";
function onMouseOver(): TestEvent { return "onmouseover"; }
let x = onMouseOver();