Skip to content

Commit eb7bbfb

Browse files
committed
Properties with numeric names have numeric literal types in keyof T
1 parent 5f0d880 commit eb7bbfb

File tree

1 file changed

+36
-49
lines changed

1 file changed

+36
-49
lines changed

src/compiler/checker.ts

Lines changed: 36 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -8206,12 +8206,15 @@ namespace ts {
82068206

82078207
function getLiteralTypeFromPropertyName(prop: Symbol, include: TypeFlags) {
82088208
if (!(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) {
8209-
const nameType = getLateBoundSymbol(prop).nameType;
8210-
if (nameType) {
8211-
return nameType.flags & include ? nameType : neverType;
8212-
}
8213-
if (!isKnownSymbol(prop)) {
8214-
return getLiteralType(symbolName(prop));
8209+
let type = getLateBoundSymbol(prop).nameType;
8210+
if (!type && !isKnownSymbol(prop)) {
8211+
const name = getNameOfDeclaration(prop.valueDeclaration);
8212+
type = name && isNumericLiteral(name) ? getLiteralType(+name.text) :
8213+
name && name.kind === SyntaxKind.ComputedPropertyName && isNumericLiteral(name.expression) ? getLiteralType(+name.expression.text) :
8214+
getLiteralType(symbolName(prop));
8215+
}
8216+
if (type && type.flags & include) {
8217+
return type;
82158218
}
82168219
}
82178220
return neverType;
@@ -15369,6 +15372,7 @@ namespace ts {
1536915372
let patternWithComputedProperties = false;
1537015373
let hasComputedStringProperty = false;
1537115374
let hasComputedNumberProperty = false;
15375+
1537215376
if (isInJSFile && node.properties.length === 0) {
1537315377
// an empty JS object literal that nonetheless has members is a JS namespace
1537415378
const symbol = getSymbolOfNode(node);
@@ -15384,47 +15388,28 @@ namespace ts {
1538415388
for (let i = 0; i < node.properties.length; i++) {
1538515389
const memberDecl = node.properties[i];
1538615390
let member = getSymbolOfNode(memberDecl);
15387-
let literalName: __String | undefined;
15391+
const computedNameType = memberDecl.name && memberDecl.name.kind === SyntaxKind.ComputedPropertyName && !isWellKnownSymbolSyntactically(memberDecl.name.expression) ?
15392+
checkComputedPropertyName(memberDecl.name) : undefined;
1538815393
if (memberDecl.kind === SyntaxKind.PropertyAssignment ||
1538915394
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ||
1539015395
isObjectLiteralMethod(memberDecl)) {
15391-
let jsdocType: Type;
15396+
let type = memberDecl.kind === SyntaxKind.PropertyAssignment ? checkPropertyAssignment(memberDecl, checkMode) :
15397+
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ? checkExpressionForMutableLocation(memberDecl.name, checkMode) :
15398+
checkObjectLiteralMethod(memberDecl, checkMode);
1539215399
if (isInJSFile) {
15393-
jsdocType = getTypeForDeclarationFromJSDocComment(memberDecl);
15394-
}
15395-
15396-
let type: Type;
15397-
if (memberDecl.kind === SyntaxKind.PropertyAssignment) {
15398-
if (memberDecl.name.kind === SyntaxKind.ComputedPropertyName) {
15399-
const t = checkComputedPropertyName(memberDecl.name);
15400-
if (t.flags & TypeFlags.Literal) {
15401-
literalName = escapeLeadingUnderscores("" + (t as LiteralType).value);
15402-
}
15400+
const jsDocType = getTypeForDeclarationFromJSDocComment(memberDecl);
15401+
if (jsDocType) {
15402+
checkTypeAssignableTo(type, jsDocType, memberDecl);
15403+
type = jsDocType;
1540315404
}
15404-
type = checkPropertyAssignment(memberDecl, checkMode);
1540515405
}
15406-
else if (memberDecl.kind === SyntaxKind.MethodDeclaration) {
15407-
type = checkObjectLiteralMethod(memberDecl, checkMode);
15408-
}
15409-
else {
15410-
Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment);
15411-
type = checkExpressionForMutableLocation(memberDecl.name, checkMode);
15412-
}
15413-
15414-
if (jsdocType) {
15415-
checkTypeAssignableTo(type, jsdocType, memberDecl);
15416-
type = jsdocType;
15417-
}
15418-
1541915406
typeFlags |= type.flags;
15420-
15421-
const nameType = hasLateBindableName(memberDecl) ? checkComputedPropertyName(memberDecl.name) : undefined;
15422-
const hasLateBoundName = nameType && isTypeUsableAsLateBoundName(nameType);
15423-
const prop = hasLateBoundName
15424-
? createSymbol(SymbolFlags.Property | member.flags, getLateBoundNameFromType(nameType as LiteralType | UniqueESSymbolType), CheckFlags.Late)
15425-
: createSymbol(SymbolFlags.Property | member.flags, literalName || member.escapedName);
15426-
15427-
if (hasLateBoundName) {
15407+
const nameType = computedNameType && computedNameType.flags & TypeFlags.StringOrNumberLiteralOrUnique ?
15408+
<LiteralType | UniqueESSymbolType>computedNameType : undefined;
15409+
const prop = nameType ?
15410+
createSymbol(SymbolFlags.Property | member.flags, getLateBoundNameFromType(nameType), CheckFlags.Late) :
15411+
createSymbol(SymbolFlags.Property | member.flags, member.escapedName);
15412+
if (nameType) {
1542815413
prop.nameType = nameType;
1542915414
}
1543015415

@@ -15437,9 +15422,6 @@ namespace ts {
1543715422
if (isOptional) {
1543815423
prop.flags |= SymbolFlags.Optional;
1543915424
}
15440-
if (!literalName && hasDynamicName(memberDecl)) {
15441-
patternWithComputedProperties = true;
15442-
}
1544315425
}
1544415426
else if (contextualTypeHasPattern && !(getObjectFlags(contextualType) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) {
1544515427
// If object literal is contextually typed by the implied type of a binding pattern, and if the
@@ -15495,12 +15477,17 @@ namespace ts {
1549515477
checkNodeDeferred(memberDecl);
1549615478
}
1549715479

15498-
if (!literalName && hasNonBindableDynamicName(memberDecl)) {
15499-
if (isNumericName(memberDecl.name)) {
15500-
hasComputedNumberProperty = true;
15501-
}
15502-
else {
15503-
hasComputedStringProperty = true;
15480+
if (computedNameType && !(computedNameType.flags & TypeFlags.StringOrNumberLiteralOrUnique)) {
15481+
if (isTypeAssignableTo(computedNameType, stringNumberSymbolType)) {
15482+
if (isTypeAssignableTo(computedNameType, numberType)) {
15483+
hasComputedNumberProperty = true;
15484+
}
15485+
else {
15486+
hasComputedStringProperty = true;
15487+
}
15488+
if (inDestructuringPattern) {
15489+
patternWithComputedProperties = true;
15490+
}
1550415491
}
1550515492
}
1550615493
else {

0 commit comments

Comments
 (0)