mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Widen widening literal types through compound-like assignments (#52493)
This commit is contained in:
parent
b8b0d26cb9
commit
cac899d44d
@ -554,6 +554,7 @@ import {
|
||||
isImportOrExportSpecifier,
|
||||
isImportSpecifier,
|
||||
isImportTypeNode,
|
||||
isInCompoundLikeAssignment,
|
||||
isIndexedAccessTypeNode,
|
||||
isInExpressionContext,
|
||||
isInfinityOrNaNString,
|
||||
@ -26729,10 +26730,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const assignedType = getWidenedLiteralType(getInitialOrAssignedType(flow));
|
||||
return isTypeAssignableTo(assignedType, declaredType) ? assignedType : anyArrayType;
|
||||
}
|
||||
if (declaredType.flags & TypeFlags.Union) {
|
||||
return getAssignmentReducedType(declaredType as UnionType, getInitialOrAssignedType(flow));
|
||||
const t = isInCompoundLikeAssignment(node) ? getBaseTypeOfLiteralType(declaredType) : declaredType;
|
||||
if (t.flags & TypeFlags.Union) {
|
||||
return getAssignmentReducedType(t as UnionType, getInitialOrAssignedType(flow));
|
||||
}
|
||||
return declaredType;
|
||||
return t;
|
||||
}
|
||||
// We didn't have a direct match. However, if the reference is a dotted name, this
|
||||
// may be an assignment to a left hand part of the reference. For example, for a
|
||||
@ -28079,7 +28081,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// entities we simply return the declared type.
|
||||
if (localOrExportSymbol.flags & SymbolFlags.Variable) {
|
||||
if (assignmentKind === AssignmentKind.Definite) {
|
||||
return type;
|
||||
return isInCompoundLikeAssignment(node) ? getBaseTypeOfLiteralType(type) : type;
|
||||
}
|
||||
}
|
||||
else if (isAlias) {
|
||||
|
||||
@ -1222,7 +1222,8 @@ function isShiftOperator(kind: SyntaxKind): kind is ShiftOperator {
|
||||
|| kind === SyntaxKind.GreaterThanGreaterThanGreaterThanToken;
|
||||
}
|
||||
|
||||
function isShiftOperatorOrHigher(kind: SyntaxKind): kind is ShiftOperatorOrHigher {
|
||||
/** @internal */
|
||||
export function isShiftOperatorOrHigher(kind: SyntaxKind): kind is ShiftOperatorOrHigher {
|
||||
return isShiftOperator(kind)
|
||||
|| isAdditiveOperatorOrHigher(kind);
|
||||
}
|
||||
|
||||
@ -152,8 +152,6 @@ import {
|
||||
forEachChild,
|
||||
forEachChildRecursively,
|
||||
ForInOrOfStatement,
|
||||
ForInStatement,
|
||||
ForOfStatement,
|
||||
ForStatement,
|
||||
FunctionBody,
|
||||
FunctionDeclaration,
|
||||
@ -331,6 +329,7 @@ import {
|
||||
isQualifiedName,
|
||||
isRootedDiskPath,
|
||||
isSetAccessorDeclaration,
|
||||
isShiftOperatorOrHigher,
|
||||
isShorthandPropertyAssignment,
|
||||
isSourceFile,
|
||||
isString,
|
||||
@ -3418,9 +3417,9 @@ export function isInExpressionContext(node: Node): boolean {
|
||||
forStatement.incrementor === node;
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
const forInStatement = parent as ForInStatement | ForOfStatement;
|
||||
return (forInStatement.initializer === node && forInStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) ||
|
||||
forInStatement.expression === node;
|
||||
const forInOrOfStatement = parent as ForInOrOfStatement;
|
||||
return (forInOrOfStatement.initializer === node && forInOrOfStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) ||
|
||||
forInOrOfStatement.expression === node;
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
case SyntaxKind.AsExpression:
|
||||
return node === (parent as AssertionExpression).expression;
|
||||
@ -4468,23 +4467,29 @@ export const enum AssignmentKind {
|
||||
None, Definite, Compound
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getAssignmentTargetKind(node: Node): AssignmentKind {
|
||||
type AssignmentTarget =
|
||||
| BinaryExpression
|
||||
| PrefixUnaryExpression
|
||||
| PostfixUnaryExpression
|
||||
| ForInOrOfStatement;
|
||||
|
||||
function getAssignmentTarget(node: Node): AssignmentTarget | undefined {
|
||||
let parent = node.parent;
|
||||
while (true) {
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
const binaryOperator = (parent as BinaryExpression).operatorToken.kind;
|
||||
return isAssignmentOperator(binaryOperator) && (parent as BinaryExpression).left === node ?
|
||||
binaryOperator === SyntaxKind.EqualsToken || isLogicalOrCoalescingAssignmentOperator(binaryOperator) ? AssignmentKind.Definite : AssignmentKind.Compound :
|
||||
AssignmentKind.None;
|
||||
const binaryExpression = parent as BinaryExpression;
|
||||
const binaryOperator = binaryExpression.operatorToken.kind;
|
||||
return isAssignmentOperator(binaryOperator) && binaryExpression.left === node ? binaryExpression : undefined;
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
const unaryOperator = (parent as PrefixUnaryExpression | PostfixUnaryExpression).operator;
|
||||
return unaryOperator === SyntaxKind.PlusPlusToken || unaryOperator === SyntaxKind.MinusMinusToken ? AssignmentKind.Compound : AssignmentKind.None;
|
||||
const unaryExpression = (parent as PrefixUnaryExpression | PostfixUnaryExpression);
|
||||
const unaryOperator = unaryExpression.operator;
|
||||
return unaryOperator === SyntaxKind.PlusPlusToken || unaryOperator === SyntaxKind.MinusMinusToken ? unaryExpression : undefined;
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
return (parent as ForInOrOfStatement).initializer === node ? AssignmentKind.Definite : AssignmentKind.None;
|
||||
const forInOrOfStatement = parent as ForInOrOfStatement;
|
||||
return forInOrOfStatement.initializer === node ? forInOrOfStatement : undefined;
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
case SyntaxKind.SpreadElement:
|
||||
@ -4496,30 +4501,62 @@ export function getAssignmentTargetKind(node: Node): AssignmentKind {
|
||||
break;
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
if ((parent as ShorthandPropertyAssignment).name !== node) {
|
||||
return AssignmentKind.None;
|
||||
return undefined;
|
||||
}
|
||||
node = parent.parent;
|
||||
break;
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
if ((parent as ShorthandPropertyAssignment).name === node) {
|
||||
return AssignmentKind.None;
|
||||
if ((parent as PropertyAssignment).name === node) {
|
||||
return undefined;
|
||||
}
|
||||
node = parent.parent;
|
||||
break;
|
||||
default:
|
||||
return AssignmentKind.None;
|
||||
return undefined;
|
||||
}
|
||||
parent = node.parent;
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getAssignmentTargetKind(node: Node): AssignmentKind {
|
||||
const target = getAssignmentTarget(node);
|
||||
if (!target) {
|
||||
return AssignmentKind.None;
|
||||
}
|
||||
switch (target.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
const binaryOperator = target.operatorToken.kind;
|
||||
return binaryOperator === SyntaxKind.EqualsToken || isLogicalOrCoalescingAssignmentOperator(binaryOperator) ?
|
||||
AssignmentKind.Definite :
|
||||
AssignmentKind.Compound;
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
return AssignmentKind.Compound;
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
return AssignmentKind.Definite;
|
||||
}
|
||||
}
|
||||
|
||||
// A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property
|
||||
// assignment in an object literal that is an assignment target, or if it is parented by an array literal that is
|
||||
// an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ a }] = xxx'.
|
||||
// (Note that `p` is not a target in the above examples, only `a`.)
|
||||
/** @internal */
|
||||
export function isAssignmentTarget(node: Node): boolean {
|
||||
return getAssignmentTargetKind(node) !== AssignmentKind.None;
|
||||
return !!getAssignmentTarget(node);
|
||||
}
|
||||
|
||||
function isCompoundLikeAssignment(assignment: AssignmentExpression<EqualsToken>): boolean {
|
||||
const right = skipParentheses(assignment.right);
|
||||
return right.kind === SyntaxKind.BinaryExpression && isShiftOperatorOrHigher((right as BinaryExpression).operatorToken.kind);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isInCompoundLikeAssignment(node: Node): boolean {
|
||||
const target = getAssignmentTarget(node);
|
||||
return !!target && isAssignmentExpression(target, /*excludeCompoundAssignment*/ true) && isCompoundLikeAssignment(target);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@ -4534,8 +4571,7 @@ export type NodeWithPossibleHoistedDeclaration =
|
||||
| DefaultClause
|
||||
| LabeledStatement
|
||||
| ForStatement
|
||||
| ForInStatement
|
||||
| ForOfStatement
|
||||
| ForInOrOfStatement
|
||||
| DoStatement
|
||||
| WhileStatement
|
||||
| TryStatement
|
||||
|
||||
@ -0,0 +1,135 @@
|
||||
//// [tests/cases/compiler/literalWideningWithCompoundLikeAssignments.ts] ////
|
||||
|
||||
=== literalWideningWithCompoundLikeAssignments.ts ===
|
||||
// repro from #13865
|
||||
|
||||
const empty: "" = "";
|
||||
>empty : Symbol(empty, Decl(literalWideningWithCompoundLikeAssignments.ts, 2, 5))
|
||||
|
||||
let foo = empty;
|
||||
>foo : Symbol(foo, Decl(literalWideningWithCompoundLikeAssignments.ts, 3, 3))
|
||||
>empty : Symbol(empty, Decl(literalWideningWithCompoundLikeAssignments.ts, 2, 5))
|
||||
|
||||
foo = foo + "bar"
|
||||
>foo : Symbol(foo, Decl(literalWideningWithCompoundLikeAssignments.ts, 3, 3))
|
||||
>foo : Symbol(foo, Decl(literalWideningWithCompoundLikeAssignments.ts, 3, 3))
|
||||
|
||||
foo // string
|
||||
>foo : Symbol(foo, Decl(literalWideningWithCompoundLikeAssignments.ts, 3, 3))
|
||||
|
||||
declare const numLiteral: 0;
|
||||
>numLiteral : Symbol(numLiteral, Decl(literalWideningWithCompoundLikeAssignments.ts, 7, 13))
|
||||
|
||||
let t1 = numLiteral;
|
||||
>t1 : Symbol(t1, Decl(literalWideningWithCompoundLikeAssignments.ts, 9, 3))
|
||||
>numLiteral : Symbol(numLiteral, Decl(literalWideningWithCompoundLikeAssignments.ts, 7, 13))
|
||||
|
||||
t1 = t1 + 42
|
||||
>t1 : Symbol(t1, Decl(literalWideningWithCompoundLikeAssignments.ts, 9, 3))
|
||||
>t1 : Symbol(t1, Decl(literalWideningWithCompoundLikeAssignments.ts, 9, 3))
|
||||
|
||||
t1 // number
|
||||
>t1 : Symbol(t1, Decl(literalWideningWithCompoundLikeAssignments.ts, 9, 3))
|
||||
|
||||
let t2 = numLiteral;
|
||||
>t2 : Symbol(t2, Decl(literalWideningWithCompoundLikeAssignments.ts, 13, 3))
|
||||
>numLiteral : Symbol(numLiteral, Decl(literalWideningWithCompoundLikeAssignments.ts, 7, 13))
|
||||
|
||||
t2 = t2 - 42
|
||||
>t2 : Symbol(t2, Decl(literalWideningWithCompoundLikeAssignments.ts, 13, 3))
|
||||
>t2 : Symbol(t2, Decl(literalWideningWithCompoundLikeAssignments.ts, 13, 3))
|
||||
|
||||
t2 // number
|
||||
>t2 : Symbol(t2, Decl(literalWideningWithCompoundLikeAssignments.ts, 13, 3))
|
||||
|
||||
let t3 = numLiteral;
|
||||
>t3 : Symbol(t3, Decl(literalWideningWithCompoundLikeAssignments.ts, 17, 3))
|
||||
>numLiteral : Symbol(numLiteral, Decl(literalWideningWithCompoundLikeAssignments.ts, 7, 13))
|
||||
|
||||
t3 = t3 * 42
|
||||
>t3 : Symbol(t3, Decl(literalWideningWithCompoundLikeAssignments.ts, 17, 3))
|
||||
>t3 : Symbol(t3, Decl(literalWideningWithCompoundLikeAssignments.ts, 17, 3))
|
||||
|
||||
t3 // number
|
||||
>t3 : Symbol(t3, Decl(literalWideningWithCompoundLikeAssignments.ts, 17, 3))
|
||||
|
||||
let t4 = numLiteral;
|
||||
>t4 : Symbol(t4, Decl(literalWideningWithCompoundLikeAssignments.ts, 21, 3))
|
||||
>numLiteral : Symbol(numLiteral, Decl(literalWideningWithCompoundLikeAssignments.ts, 7, 13))
|
||||
|
||||
t4 = t4 ** 42
|
||||
>t4 : Symbol(t4, Decl(literalWideningWithCompoundLikeAssignments.ts, 21, 3))
|
||||
>t4 : Symbol(t4, Decl(literalWideningWithCompoundLikeAssignments.ts, 21, 3))
|
||||
|
||||
t4 // number
|
||||
>t4 : Symbol(t4, Decl(literalWideningWithCompoundLikeAssignments.ts, 21, 3))
|
||||
|
||||
let t5 = numLiteral;
|
||||
>t5 : Symbol(t5, Decl(literalWideningWithCompoundLikeAssignments.ts, 25, 3))
|
||||
>numLiteral : Symbol(numLiteral, Decl(literalWideningWithCompoundLikeAssignments.ts, 7, 13))
|
||||
|
||||
t5 = t5 / 42
|
||||
>t5 : Symbol(t5, Decl(literalWideningWithCompoundLikeAssignments.ts, 25, 3))
|
||||
>t5 : Symbol(t5, Decl(literalWideningWithCompoundLikeAssignments.ts, 25, 3))
|
||||
|
||||
t5 // number
|
||||
>t5 : Symbol(t5, Decl(literalWideningWithCompoundLikeAssignments.ts, 25, 3))
|
||||
|
||||
let t6 = numLiteral;
|
||||
>t6 : Symbol(t6, Decl(literalWideningWithCompoundLikeAssignments.ts, 29, 3))
|
||||
>numLiteral : Symbol(numLiteral, Decl(literalWideningWithCompoundLikeAssignments.ts, 7, 13))
|
||||
|
||||
t6 = t6 % 42
|
||||
>t6 : Symbol(t6, Decl(literalWideningWithCompoundLikeAssignments.ts, 29, 3))
|
||||
>t6 : Symbol(t6, Decl(literalWideningWithCompoundLikeAssignments.ts, 29, 3))
|
||||
|
||||
t6 // number
|
||||
>t6 : Symbol(t6, Decl(literalWideningWithCompoundLikeAssignments.ts, 29, 3))
|
||||
|
||||
let t7 = numLiteral;
|
||||
>t7 : Symbol(t7, Decl(literalWideningWithCompoundLikeAssignments.ts, 33, 3))
|
||||
>numLiteral : Symbol(numLiteral, Decl(literalWideningWithCompoundLikeAssignments.ts, 7, 13))
|
||||
|
||||
t7 = t7 >> 0
|
||||
>t7 : Symbol(t7, Decl(literalWideningWithCompoundLikeAssignments.ts, 33, 3))
|
||||
>t7 : Symbol(t7, Decl(literalWideningWithCompoundLikeAssignments.ts, 33, 3))
|
||||
|
||||
t7 // number
|
||||
>t7 : Symbol(t7, Decl(literalWideningWithCompoundLikeAssignments.ts, 33, 3))
|
||||
|
||||
let t8 = numLiteral;
|
||||
>t8 : Symbol(t8, Decl(literalWideningWithCompoundLikeAssignments.ts, 37, 3))
|
||||
>numLiteral : Symbol(numLiteral, Decl(literalWideningWithCompoundLikeAssignments.ts, 7, 13))
|
||||
|
||||
t8 = t8 >>> 0
|
||||
>t8 : Symbol(t8, Decl(literalWideningWithCompoundLikeAssignments.ts, 37, 3))
|
||||
>t8 : Symbol(t8, Decl(literalWideningWithCompoundLikeAssignments.ts, 37, 3))
|
||||
|
||||
t8 // number
|
||||
>t8 : Symbol(t8, Decl(literalWideningWithCompoundLikeAssignments.ts, 37, 3))
|
||||
|
||||
let t9 = numLiteral;
|
||||
>t9 : Symbol(t9, Decl(literalWideningWithCompoundLikeAssignments.ts, 41, 3))
|
||||
>numLiteral : Symbol(numLiteral, Decl(literalWideningWithCompoundLikeAssignments.ts, 7, 13))
|
||||
|
||||
t9 = t9 << 0
|
||||
>t9 : Symbol(t9, Decl(literalWideningWithCompoundLikeAssignments.ts, 41, 3))
|
||||
>t9 : Symbol(t9, Decl(literalWideningWithCompoundLikeAssignments.ts, 41, 3))
|
||||
|
||||
t9 // number
|
||||
>t9 : Symbol(t9, Decl(literalWideningWithCompoundLikeAssignments.ts, 41, 3))
|
||||
|
||||
declare const literalUnion: "a" | 0;
|
||||
>literalUnion : Symbol(literalUnion, Decl(literalWideningWithCompoundLikeAssignments.ts, 45, 13))
|
||||
|
||||
let t10 = literalUnion;
|
||||
>t10 : Symbol(t10, Decl(literalWideningWithCompoundLikeAssignments.ts, 46, 3))
|
||||
>literalUnion : Symbol(literalUnion, Decl(literalWideningWithCompoundLikeAssignments.ts, 45, 13))
|
||||
|
||||
t10 = t10 + 'b'
|
||||
>t10 : Symbol(t10, Decl(literalWideningWithCompoundLikeAssignments.ts, 46, 3))
|
||||
>t10 : Symbol(t10, Decl(literalWideningWithCompoundLikeAssignments.ts, 46, 3))
|
||||
|
||||
t10 // string
|
||||
>t10 : Symbol(t10, Decl(literalWideningWithCompoundLikeAssignments.ts, 46, 3))
|
||||
|
||||
@ -0,0 +1,169 @@
|
||||
//// [tests/cases/compiler/literalWideningWithCompoundLikeAssignments.ts] ////
|
||||
|
||||
=== literalWideningWithCompoundLikeAssignments.ts ===
|
||||
// repro from #13865
|
||||
|
||||
const empty: "" = "";
|
||||
>empty : ""
|
||||
>"" : ""
|
||||
|
||||
let foo = empty;
|
||||
>foo : ""
|
||||
>empty : ""
|
||||
|
||||
foo = foo + "bar"
|
||||
>foo = foo + "bar" : string
|
||||
>foo : string
|
||||
>foo + "bar" : string
|
||||
>foo : ""
|
||||
>"bar" : "bar"
|
||||
|
||||
foo // string
|
||||
>foo : string
|
||||
|
||||
declare const numLiteral: 0;
|
||||
>numLiteral : 0
|
||||
|
||||
let t1 = numLiteral;
|
||||
>t1 : 0
|
||||
>numLiteral : 0
|
||||
|
||||
t1 = t1 + 42
|
||||
>t1 = t1 + 42 : number
|
||||
>t1 : number
|
||||
>t1 + 42 : number
|
||||
>t1 : 0
|
||||
>42 : 42
|
||||
|
||||
t1 // number
|
||||
>t1 : number
|
||||
|
||||
let t2 = numLiteral;
|
||||
>t2 : 0
|
||||
>numLiteral : 0
|
||||
|
||||
t2 = t2 - 42
|
||||
>t2 = t2 - 42 : number
|
||||
>t2 : number
|
||||
>t2 - 42 : number
|
||||
>t2 : 0
|
||||
>42 : 42
|
||||
|
||||
t2 // number
|
||||
>t2 : number
|
||||
|
||||
let t3 = numLiteral;
|
||||
>t3 : 0
|
||||
>numLiteral : 0
|
||||
|
||||
t3 = t3 * 42
|
||||
>t3 = t3 * 42 : number
|
||||
>t3 : number
|
||||
>t3 * 42 : number
|
||||
>t3 : 0
|
||||
>42 : 42
|
||||
|
||||
t3 // number
|
||||
>t3 : number
|
||||
|
||||
let t4 = numLiteral;
|
||||
>t4 : 0
|
||||
>numLiteral : 0
|
||||
|
||||
t4 = t4 ** 42
|
||||
>t4 = t4 ** 42 : number
|
||||
>t4 : number
|
||||
>t4 ** 42 : number
|
||||
>t4 : 0
|
||||
>42 : 42
|
||||
|
||||
t4 // number
|
||||
>t4 : number
|
||||
|
||||
let t5 = numLiteral;
|
||||
>t5 : 0
|
||||
>numLiteral : 0
|
||||
|
||||
t5 = t5 / 42
|
||||
>t5 = t5 / 42 : number
|
||||
>t5 : number
|
||||
>t5 / 42 : number
|
||||
>t5 : 0
|
||||
>42 : 42
|
||||
|
||||
t5 // number
|
||||
>t5 : number
|
||||
|
||||
let t6 = numLiteral;
|
||||
>t6 : 0
|
||||
>numLiteral : 0
|
||||
|
||||
t6 = t6 % 42
|
||||
>t6 = t6 % 42 : number
|
||||
>t6 : number
|
||||
>t6 % 42 : number
|
||||
>t6 : 0
|
||||
>42 : 42
|
||||
|
||||
t6 // number
|
||||
>t6 : number
|
||||
|
||||
let t7 = numLiteral;
|
||||
>t7 : 0
|
||||
>numLiteral : 0
|
||||
|
||||
t7 = t7 >> 0
|
||||
>t7 = t7 >> 0 : number
|
||||
>t7 : number
|
||||
>t7 >> 0 : number
|
||||
>t7 : 0
|
||||
>0 : 0
|
||||
|
||||
t7 // number
|
||||
>t7 : number
|
||||
|
||||
let t8 = numLiteral;
|
||||
>t8 : 0
|
||||
>numLiteral : 0
|
||||
|
||||
t8 = t8 >>> 0
|
||||
>t8 = t8 >>> 0 : number
|
||||
>t8 : number
|
||||
>t8 >>> 0 : number
|
||||
>t8 : 0
|
||||
>0 : 0
|
||||
|
||||
t8 // number
|
||||
>t8 : number
|
||||
|
||||
let t9 = numLiteral;
|
||||
>t9 : 0
|
||||
>numLiteral : 0
|
||||
|
||||
t9 = t9 << 0
|
||||
>t9 = t9 << 0 : number
|
||||
>t9 : number
|
||||
>t9 << 0 : number
|
||||
>t9 : 0
|
||||
>0 : 0
|
||||
|
||||
t9 // number
|
||||
>t9 : number
|
||||
|
||||
declare const literalUnion: "a" | 0;
|
||||
>literalUnion : 0 | "a"
|
||||
|
||||
let t10 = literalUnion;
|
||||
>t10 : 0 | "a"
|
||||
>literalUnion : 0 | "a"
|
||||
|
||||
t10 = t10 + 'b'
|
||||
>t10 = t10 + 'b' : string
|
||||
>t10 : string | number
|
||||
>t10 + 'b' : string
|
||||
>t10 : 0 | "a"
|
||||
>'b' : "b"
|
||||
|
||||
t10 // string
|
||||
>t10 : string
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
// repro from #13865
|
||||
|
||||
const empty: "" = "";
|
||||
let foo = empty;
|
||||
foo = foo + "bar"
|
||||
foo // string
|
||||
|
||||
declare const numLiteral: 0;
|
||||
|
||||
let t1 = numLiteral;
|
||||
t1 = t1 + 42
|
||||
t1 // number
|
||||
|
||||
let t2 = numLiteral;
|
||||
t2 = t2 - 42
|
||||
t2 // number
|
||||
|
||||
let t3 = numLiteral;
|
||||
t3 = t3 * 42
|
||||
t3 // number
|
||||
|
||||
let t4 = numLiteral;
|
||||
t4 = t4 ** 42
|
||||
t4 // number
|
||||
|
||||
let t5 = numLiteral;
|
||||
t5 = t5 / 42
|
||||
t5 // number
|
||||
|
||||
let t6 = numLiteral;
|
||||
t6 = t6 % 42
|
||||
t6 // number
|
||||
|
||||
let t7 = numLiteral;
|
||||
t7 = t7 >> 0
|
||||
t7 // number
|
||||
|
||||
let t8 = numLiteral;
|
||||
t8 = t8 >>> 0
|
||||
t8 // number
|
||||
|
||||
let t9 = numLiteral;
|
||||
t9 = t9 << 0
|
||||
t9 // number
|
||||
|
||||
declare const literalUnion: "a" | 0;
|
||||
let t10 = literalUnion;
|
||||
t10 = t10 + 'b'
|
||||
t10 // string
|
||||
Loading…
x
Reference in New Issue
Block a user