Skip to content

Commit e7cfbfe

Browse files
committed
Support parametric property access expressions + some renaming
1 parent c21592e commit e7cfbfe

File tree

7 files changed

+80
-68
lines changed

7 files changed

+80
-68
lines changed

src/compiler/binder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3067,7 +3067,7 @@ namespace ts {
30673067
case SyntaxKind.TypeAliasDeclaration:
30683068
case SyntaxKind.ThisType:
30693069
case SyntaxKind.TypeOperator:
3070-
case SyntaxKind.PropertyAccessType:
3070+
case SyntaxKind.IndexedAccessType:
30713071
case SyntaxKind.LiteralType:
30723072
// Types and signatures are TypeScript syntax, and exclude all other facts.
30733073
transformFlags = TransformFlags.AssertTypeScript;

src/compiler/checker.ts

Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,15 +2219,15 @@ namespace ts {
22192219
else if (type.flags & TypeFlags.StringOrNumberLiteral) {
22202220
writer.writeStringLiteral(literalTypeToString(<LiteralType>type));
22212221
}
2222-
else if (type.flags & TypeFlags.PropertyName) {
2222+
else if (type.flags & TypeFlags.Index) {
22232223
writer.writeKeyword("keyof");
22242224
writeSpace(writer);
2225-
writeType((<PropertyNameType>type).type, TypeFormatFlags.InElementType);
2225+
writeType((<IndexType>type).type, TypeFormatFlags.InElementType);
22262226
}
2227-
else if (type.flags & TypeFlags.PropertyAccess) {
2228-
writeType((<PropertyAccessType>type).objectType, TypeFormatFlags.InElementType);
2227+
else if (type.flags & TypeFlags.IndexedAccess) {
2228+
writeType((<IndexedAccessType>type).objectType, TypeFormatFlags.InElementType);
22292229
writePunctuation(writer, SyntaxKind.OpenBracketToken);
2230-
writeType((<PropertyAccessType>type).keyType, TypeFormatFlags.None);
2230+
writeType((<IndexedAccessType>type).indexType, TypeFormatFlags.None);
22312231
writePunctuation(writer, SyntaxKind.CloseBracketToken);
22322232
}
22332233
else {
@@ -5678,73 +5678,73 @@ namespace ts {
56785678
return startsWith(prop.name, "__@") ? neverType : getLiteralTypeForText(TypeFlags.StringLiteral, unescapeIdentifier(prop.name));
56795679
}
56805680

5681-
function getPropertyNameTypeForTypeParameter(type: TypeParameter) {
5682-
if (!type.resolvedPropertyNameType) {
5683-
type.resolvedPropertyNameType = <PropertyNameType>createType(TypeFlags.PropertyName);
5684-
type.resolvedPropertyNameType.type = type;
5681+
function getIndexTypeForTypeParameter(type: TypeParameter) {
5682+
if (!type.resolvedIndexType) {
5683+
type.resolvedIndexType = <IndexType>createType(TypeFlags.Index);
5684+
type.resolvedIndexType.type = type;
56855685
}
5686-
return type.resolvedPropertyNameType;
5686+
return type.resolvedIndexType;
56875687
}
56885688

5689-
function getPropertyNameType(type: Type): Type {
5689+
function getIndexType(type: Type): Type {
56905690
return type.flags & TypeFlags.TypeParameter ?
5691-
getPropertyNameTypeForTypeParameter(<TypeParameter>type) :
5691+
getIndexTypeForTypeParameter(<TypeParameter>type) :
56925692
getUnionType(map(getPropertiesOfType(type), getLiteralTypeFromPropertyName));
56935693
}
56945694

56955695
function getTypeFromTypeOperatorNode(node: TypeOperatorNode) {
56965696
const links = getNodeLinks(node);
56975697
if (!links.resolvedType) {
5698-
links.resolvedType = getPropertyNameType(getTypeFromTypeNodeNoAlias(node.type));
5698+
links.resolvedType = getIndexType(getTypeFromTypeNodeNoAlias(node.type));
56995699
}
57005700
return links.resolvedType;
57015701
}
57025702

5703-
function createPropertyAccessType(objectType: Type, keyType: TypeParameter) {
5704-
const type = <PropertyAccessType>createType(TypeFlags.PropertyAccess);
5703+
function createIndexedAccessType(objectType: Type, keyType: TypeParameter) {
5704+
const type = <IndexedAccessType>createType(TypeFlags.IndexedAccess);
57055705
type.objectType = objectType;
5706-
type.keyType = keyType;
5706+
type.indexType = keyType;
57075707
return type;
57085708
}
57095709

5710-
function getPropertyAccessTypeForTypeParameter(objectType: Type, keyType: TypeParameter) {
5711-
const propertyAccessTypes = keyType.resolvedPropertyAccessTypes || (keyType.resolvedPropertyAccessTypes = []);
5712-
return propertyAccessTypes[objectType.id] || (propertyAccessTypes[objectType.id] = createPropertyAccessType(objectType, keyType));
5710+
function getIndexedAccessTypeForTypeParameter(objectType: Type, keyType: TypeParameter) {
5711+
const indexedAccessTypes = keyType.resolvedIndexedAccessTypes || (keyType.resolvedIndexedAccessTypes = []);
5712+
return indexedAccessTypes[objectType.id] || (indexedAccessTypes[objectType.id] = createIndexedAccessType(objectType, keyType));
57135713
}
57145714

5715-
function getPropertyAccessType(objectType: Type, keyType: Type) {
5715+
function getIndexedAccessType(objectType: Type, keyType: Type) {
57165716
if (keyType.flags & TypeFlags.TypeParameter) {
5717-
return getPropertyAccessTypeForTypeParameter(objectType, <TypeParameter>keyType);
5717+
return getIndexedAccessTypeForTypeParameter(objectType, <TypeParameter>keyType);
57185718
}
57195719
if (isTypeOfKind(keyType, TypeFlags.StringLiteral) && !(keyType.flags & TypeFlags.Intersection)) {
57205720
return mapType(keyType, t => getTypeOfPropertyOfType(objectType, escapeIdentifier((<LiteralType>t).text)) || unknownType);
57215721
}
57225722
return keyType.flags & TypeFlags.Any ? anyType : unknownType;
57235723
}
57245724

5725-
function resolvePropertyAccessTypeNode(node: PropertyAccessTypeNode) {
5725+
function resolveIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
57265726
const objectType = getTypeFromTypeNodeNoAlias(node.objectType);
5727-
const keyType = getTypeFromTypeNodeNoAlias(node.keyType);
5727+
const keyType = getTypeFromTypeNodeNoAlias(node.indexType);
57285728
if (keyType.flags & TypeFlags.TypeParameter &&
5729-
getConstraintOfTypeParameter(<TypeParameter>keyType) === getPropertyNameType(objectType)) {
5730-
return getPropertyAccessType(objectType, keyType);
5729+
getConstraintOfTypeParameter(<TypeParameter>keyType) === getIndexType(objectType)) {
5730+
return getIndexedAccessType(objectType, keyType);
57315731
}
57325732
if (isTypeOfKind(keyType, TypeFlags.StringLiteral) && !(keyType.flags & TypeFlags.Intersection)) {
57335733
const missing = forEachType(keyType, t => getTypeOfPropertyOfType(objectType, escapeIdentifier((<LiteralType>t).text)) ? undefined : (<LiteralType>t).text);
57345734
if (missing) {
5735-
error(node.keyType, Diagnostics.Property_0_is_missing_in_type_1, missing, typeToString(objectType));
5735+
error(node.indexType, Diagnostics.Property_0_is_missing_in_type_1, missing, typeToString(objectType));
57365736
return unknownType;
57375737
}
5738-
return getPropertyAccessType(objectType, keyType);
5738+
return getIndexedAccessType(objectType, keyType);
57395739
}
5740-
error(node.keyType, Diagnostics.Property_access_element_type_must_be_a_string_literal_type_or_a_type_parameter_constrained_to_keyof_0, typeToString(objectType));
5740+
error(node.indexType, Diagnostics.Property_access_element_type_must_be_a_string_literal_type_or_a_type_parameter_constrained_to_keyof_0, typeToString(objectType));
57415741
return unknownType;
57425742
}
57435743

5744-
function getTypeFromPropertyAccessTypeNode(node: PropertyAccessTypeNode) {
5744+
function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
57455745
const links = getNodeLinks(node);
57465746
if (!links.resolvedType) {
5747-
links.resolvedType = resolvePropertyAccessTypeNode(node);
5747+
links.resolvedType = resolveIndexedAccessTypeNode(node);
57485748
}
57495749
return links.resolvedType;
57505750
}
@@ -5910,8 +5910,8 @@ namespace ts {
59105910
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node, aliasSymbol, aliasTypeArguments);
59115911
case SyntaxKind.TypeOperator:
59125912
return getTypeFromTypeOperatorNode(<TypeOperatorNode>node);
5913-
case SyntaxKind.PropertyAccessType:
5914-
return getTypeFromPropertyAccessTypeNode(<PropertyAccessTypeNode>node);
5913+
case SyntaxKind.IndexedAccessType:
5914+
return getTypeFromIndexedAccessTypeNode(<IndexedAccessTypeNode>node);
59155915
// This function assumes that an identifier or qualified name is a type expression
59165916
// Callers should first ensure this by calling isTypeNode
59175917
case SyntaxKind.Identifier:
@@ -6173,11 +6173,11 @@ namespace ts {
61736173
if (type.flags & TypeFlags.Intersection) {
61746174
return getIntersectionType(instantiateList((<IntersectionType>type).types, mapper, instantiateType), type.aliasSymbol, mapper.targetTypes);
61756175
}
6176-
if (type.flags & TypeFlags.PropertyName) {
6177-
return getPropertyNameType(instantiateType((<PropertyNameType>type).type, mapper));
6176+
if (type.flags & TypeFlags.Index) {
6177+
return getIndexType(instantiateType((<IndexType>type).type, mapper));
61786178
}
6179-
if (type.flags & TypeFlags.PropertyAccess) {
6180-
return getPropertyAccessType(instantiateType((<PropertyAccessType>type).objectType, mapper), instantiateType((<PropertyAccessType>type).keyType, mapper));
6179+
if (type.flags & TypeFlags.IndexedAccess) {
6180+
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
61816181
}
61826182
}
61836183
return type;
@@ -8114,7 +8114,7 @@ namespace ts {
81148114

81158115
function hasPrimitiveConstraint(type: TypeParameter): boolean {
81168116
const constraint = getConstraintOfTypeParameter(type);
8117-
return constraint && maybeTypeOfKind(constraint, TypeFlags.Primitive | TypeFlags.PropertyName);
8117+
return constraint && maybeTypeOfKind(constraint, TypeFlags.Primitive | TypeFlags.Index);
81188118
}
81198119

81208120
function getInferredType(context: InferenceContext, index: number): Type {
@@ -11520,14 +11520,20 @@ namespace ts {
1152011520
}
1152111521
}
1152211522

11523-
// Obtain base constraint such that we can bail out if the constraint is an unknown type
11524-
const objectType = getApparentType(checkNonNullExpression(node.expression));
11523+
let objectType = checkNonNullExpression(node.expression);
1152511524
const indexType = node.argumentExpression ? checkExpression(node.argumentExpression) : unknownType;
1152611525

1152711526
if (objectType === unknownType || objectType === silentNeverType) {
1152811527
return objectType;
1152911528
}
1153011529

11530+
if (indexType.flags & TypeFlags.TypeParameter &&
11531+
isTypeAssignableTo(getConstraintOfTypeParameter(<TypeParameter>indexType), getIndexType(objectType))) {
11532+
return getIndexedAccessType(objectType, indexType);
11533+
}
11534+
11535+
objectType = getApparentType(objectType);
11536+
1153111537
const isConstEnum = isConstEnumObjectType(objectType);
1153211538
if (isConstEnum &&
1153311539
(!node.argumentExpression || node.argumentExpression.kind !== SyntaxKind.StringLiteral)) {
@@ -15043,6 +15049,10 @@ namespace ts {
1504315049
forEach(node.types, checkSourceElement);
1504415050
}
1504515051

15052+
function checkIndexedAccessType(node: IndexedAccessTypeNode) {
15053+
getTypeFromIndexedAccessTypeNode(node);
15054+
}
15055+
1504615056
function isPrivateWithinAmbient(node: Node): boolean {
1504715057
return (getModifierFlags(node) & ModifierFlags.Private) && isInAmbientContext(node);
1504815058
}
@@ -18327,6 +18337,8 @@ namespace ts {
1832718337
case SyntaxKind.ParenthesizedType:
1832818338
case SyntaxKind.TypeOperator:
1832918339
return checkSourceElement((<ParenthesizedTypeNode | TypeOperatorNode>node).type);
18340+
case SyntaxKind.IndexedAccessType:
18341+
return checkIndexedAccessType(<IndexedAccessTypeNode>node);
1833018342
case SyntaxKind.FunctionDeclaration:
1833118343
return checkFunctionDeclaration(<FunctionDeclaration>node);
1833218344
case SyntaxKind.Block:

src/compiler/declarationEmitter.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,8 @@ namespace ts {
415415
return emitParenType(<ParenthesizedTypeNode>type);
416416
case SyntaxKind.TypeOperator:
417417
return emitTypeOperator(<TypeOperatorNode>type);
418-
case SyntaxKind.PropertyAccessType:
419-
return emitPropertyAccessType(<PropertyAccessTypeNode>type);
418+
case SyntaxKind.IndexedAccessType:
419+
return emitPropertyAccessType(<IndexedAccessTypeNode>type);
420420
case SyntaxKind.FunctionType:
421421
case SyntaxKind.ConstructorType:
422422
return emitSignatureDeclarationWithJsDocComments(<FunctionOrConstructorTypeNode>type);
@@ -516,10 +516,10 @@ namespace ts {
516516
emitType(type.type);
517517
}
518518

519-
function emitPropertyAccessType(node: PropertyAccessTypeNode) {
519+
function emitPropertyAccessType(node: IndexedAccessTypeNode) {
520520
emitType(node.objectType);
521521
write("[");
522-
emitType(node.keyType);
522+
emitType(node.indexType);
523523
write("]");
524524
}
525525

src/compiler/emitter.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -596,8 +596,8 @@ const _super = (function (geti, seti) {
596596
return emitThisType();
597597
case SyntaxKind.TypeOperator:
598598
return emitTypeOperator(<TypeOperatorNode>node);
599-
case SyntaxKind.PropertyAccessType:
600-
return emitPropertyAccessType(<PropertyAccessTypeNode>node);
599+
case SyntaxKind.IndexedAccessType:
600+
return emitPropertyAccessType(<IndexedAccessTypeNode>node);
601601
case SyntaxKind.LiteralType:
602602
return emitLiteralType(<LiteralTypeNode>node);
603603

@@ -1098,10 +1098,10 @@ const _super = (function (geti, seti) {
10981098
emit(node.type);
10991099
}
11001100

1101-
function emitPropertyAccessType(node: PropertyAccessTypeNode) {
1101+
function emitPropertyAccessType(node: IndexedAccessTypeNode) {
11021102
emit(node.objectType);
11031103
write("[");
1104-
emit(node.keyType);
1104+
emit(node.indexType);
11051105
write("]");
11061106
}
11071107

src/compiler/parser.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,9 @@ namespace ts {
136136
case SyntaxKind.ParenthesizedType:
137137
case SyntaxKind.TypeOperator:
138138
return visitNode(cbNode, (<ParenthesizedTypeNode | TypeOperatorNode>node).type);
139-
case SyntaxKind.PropertyAccessType:
140-
return visitNode(cbNode, (<PropertyAccessTypeNode>node).objectType) ||
141-
visitNode(cbNode, (<PropertyAccessTypeNode>node).keyType);
139+
case SyntaxKind.IndexedAccessType:
140+
return visitNode(cbNode, (<IndexedAccessTypeNode>node).objectType) ||
141+
visitNode(cbNode, (<IndexedAccessTypeNode>node).indexType);
142142
case SyntaxKind.LiteralType:
143143
return visitNode(cbNode, (<LiteralTypeNode>node).literal);
144144
case SyntaxKind.ObjectBindingPattern:
@@ -2523,9 +2523,9 @@ namespace ts {
25232523
let type = parseNonArrayType();
25242524
while (!scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.OpenBracketToken)) {
25252525
if (isStartOfType()) {
2526-
const node = <PropertyAccessTypeNode>createNode(SyntaxKind.PropertyAccessType, type.pos);
2526+
const node = <IndexedAccessTypeNode>createNode(SyntaxKind.IndexedAccessType, type.pos);
25272527
node.objectType = type;
2528-
node.keyType = parseType();
2528+
node.indexType = parseType();
25292529
parseExpected(SyntaxKind.CloseBracketToken);
25302530
type = finishNode(node);
25312531
}

src/compiler/transformers/ts.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ namespace ts {
289289
case SyntaxKind.ParenthesizedType:
290290
case SyntaxKind.ThisType:
291291
case SyntaxKind.TypeOperator:
292-
case SyntaxKind.PropertyAccessType:
292+
case SyntaxKind.IndexedAccessType:
293293
case SyntaxKind.LiteralType:
294294
// TypeScript type nodes are elided.
295295

@@ -1859,7 +1859,7 @@ namespace ts {
18591859
// Fallthrough
18601860
case SyntaxKind.TypeQuery:
18611861
case SyntaxKind.TypeOperator:
1862-
case SyntaxKind.PropertyAccessType:
1862+
case SyntaxKind.IndexedAccessType:
18631863
case SyntaxKind.TypeLiteral:
18641864
case SyntaxKind.AnyKeyword:
18651865
case SyntaxKind.ThisType:

0 commit comments

Comments
 (0)