mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-06 02:13:31 -06:00
Properties with numeric names have numeric literal types in keyof T
This commit is contained in:
parent
5f0d88096c
commit
eb7bbfb28e
@ -8206,12 +8206,15 @@ namespace ts {
|
||||
|
||||
function getLiteralTypeFromPropertyName(prop: Symbol, include: TypeFlags) {
|
||||
if (!(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) {
|
||||
const nameType = getLateBoundSymbol(prop).nameType;
|
||||
if (nameType) {
|
||||
return nameType.flags & include ? nameType : neverType;
|
||||
let type = getLateBoundSymbol(prop).nameType;
|
||||
if (!type && !isKnownSymbol(prop)) {
|
||||
const name = getNameOfDeclaration(prop.valueDeclaration);
|
||||
type = name && isNumericLiteral(name) ? getLiteralType(+name.text) :
|
||||
name && name.kind === SyntaxKind.ComputedPropertyName && isNumericLiteral(name.expression) ? getLiteralType(+name.expression.text) :
|
||||
getLiteralType(symbolName(prop));
|
||||
}
|
||||
if (!isKnownSymbol(prop)) {
|
||||
return getLiteralType(symbolName(prop));
|
||||
if (type && type.flags & include) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return neverType;
|
||||
@ -15369,6 +15372,7 @@ namespace ts {
|
||||
let patternWithComputedProperties = false;
|
||||
let hasComputedStringProperty = false;
|
||||
let hasComputedNumberProperty = false;
|
||||
|
||||
if (isInJSFile && node.properties.length === 0) {
|
||||
// an empty JS object literal that nonetheless has members is a JS namespace
|
||||
const symbol = getSymbolOfNode(node);
|
||||
@ -15384,47 +15388,28 @@ namespace ts {
|
||||
for (let i = 0; i < node.properties.length; i++) {
|
||||
const memberDecl = node.properties[i];
|
||||
let member = getSymbolOfNode(memberDecl);
|
||||
let literalName: __String | undefined;
|
||||
const computedNameType = memberDecl.name && memberDecl.name.kind === SyntaxKind.ComputedPropertyName && !isWellKnownSymbolSyntactically(memberDecl.name.expression) ?
|
||||
checkComputedPropertyName(memberDecl.name) : undefined;
|
||||
if (memberDecl.kind === SyntaxKind.PropertyAssignment ||
|
||||
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ||
|
||||
isObjectLiteralMethod(memberDecl)) {
|
||||
let jsdocType: Type;
|
||||
let type = memberDecl.kind === SyntaxKind.PropertyAssignment ? checkPropertyAssignment(memberDecl, checkMode) :
|
||||
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ? checkExpressionForMutableLocation(memberDecl.name, checkMode) :
|
||||
checkObjectLiteralMethod(memberDecl, checkMode);
|
||||
if (isInJSFile) {
|
||||
jsdocType = getTypeForDeclarationFromJSDocComment(memberDecl);
|
||||
}
|
||||
|
||||
let type: Type;
|
||||
if (memberDecl.kind === SyntaxKind.PropertyAssignment) {
|
||||
if (memberDecl.name.kind === SyntaxKind.ComputedPropertyName) {
|
||||
const t = checkComputedPropertyName(memberDecl.name);
|
||||
if (t.flags & TypeFlags.Literal) {
|
||||
literalName = escapeLeadingUnderscores("" + (t as LiteralType).value);
|
||||
}
|
||||
const jsDocType = getTypeForDeclarationFromJSDocComment(memberDecl);
|
||||
if (jsDocType) {
|
||||
checkTypeAssignableTo(type, jsDocType, memberDecl);
|
||||
type = jsDocType;
|
||||
}
|
||||
type = checkPropertyAssignment(memberDecl, checkMode);
|
||||
}
|
||||
else if (memberDecl.kind === SyntaxKind.MethodDeclaration) {
|
||||
type = checkObjectLiteralMethod(memberDecl, checkMode);
|
||||
}
|
||||
else {
|
||||
Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment);
|
||||
type = checkExpressionForMutableLocation(memberDecl.name, checkMode);
|
||||
}
|
||||
|
||||
if (jsdocType) {
|
||||
checkTypeAssignableTo(type, jsdocType, memberDecl);
|
||||
type = jsdocType;
|
||||
}
|
||||
|
||||
typeFlags |= type.flags;
|
||||
|
||||
const nameType = hasLateBindableName(memberDecl) ? checkComputedPropertyName(memberDecl.name) : undefined;
|
||||
const hasLateBoundName = nameType && isTypeUsableAsLateBoundName(nameType);
|
||||
const prop = hasLateBoundName
|
||||
? createSymbol(SymbolFlags.Property | member.flags, getLateBoundNameFromType(nameType as LiteralType | UniqueESSymbolType), CheckFlags.Late)
|
||||
: createSymbol(SymbolFlags.Property | member.flags, literalName || member.escapedName);
|
||||
|
||||
if (hasLateBoundName) {
|
||||
const nameType = computedNameType && computedNameType.flags & TypeFlags.StringOrNumberLiteralOrUnique ?
|
||||
<LiteralType | UniqueESSymbolType>computedNameType : undefined;
|
||||
const prop = nameType ?
|
||||
createSymbol(SymbolFlags.Property | member.flags, getLateBoundNameFromType(nameType), CheckFlags.Late) :
|
||||
createSymbol(SymbolFlags.Property | member.flags, member.escapedName);
|
||||
if (nameType) {
|
||||
prop.nameType = nameType;
|
||||
}
|
||||
|
||||
@ -15437,9 +15422,6 @@ namespace ts {
|
||||
if (isOptional) {
|
||||
prop.flags |= SymbolFlags.Optional;
|
||||
}
|
||||
if (!literalName && hasDynamicName(memberDecl)) {
|
||||
patternWithComputedProperties = true;
|
||||
}
|
||||
}
|
||||
else if (contextualTypeHasPattern && !(getObjectFlags(contextualType) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) {
|
||||
// If object literal is contextually typed by the implied type of a binding pattern, and if the
|
||||
@ -15495,12 +15477,17 @@ namespace ts {
|
||||
checkNodeDeferred(memberDecl);
|
||||
}
|
||||
|
||||
if (!literalName && hasNonBindableDynamicName(memberDecl)) {
|
||||
if (isNumericName(memberDecl.name)) {
|
||||
hasComputedNumberProperty = true;
|
||||
}
|
||||
else {
|
||||
hasComputedStringProperty = true;
|
||||
if (computedNameType && !(computedNameType.flags & TypeFlags.StringOrNumberLiteralOrUnique)) {
|
||||
if (isTypeAssignableTo(computedNameType, stringNumberSymbolType)) {
|
||||
if (isTypeAssignableTo(computedNameType, numberType)) {
|
||||
hasComputedNumberProperty = true;
|
||||
}
|
||||
else {
|
||||
hasComputedStringProperty = true;
|
||||
}
|
||||
if (inDestructuringPattern) {
|
||||
patternWithComputedProperties = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user