@@ -136,6 +136,7 @@ namespace ts {
136
136
const voidType = createIntrinsicType(TypeFlags.Void, "void");
137
137
const neverType = createIntrinsicType(TypeFlags.Never, "never");
138
138
const silentNeverType = createIntrinsicType(TypeFlags.Never, "never");
139
+ const stringOrNumberType = getUnionType([stringType, numberType]);
139
140
140
141
const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
141
142
const emptyGenericType = <GenericType><ObjectType>createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
@@ -4473,22 +4474,13 @@ namespace ts {
4473
4474
* type itself. Note that the apparent type of a union type is the union type itself.
4474
4475
*/
4475
4476
function getApparentType(type: Type): Type {
4476
- if (type.flags & TypeFlags.TypeParameter) {
4477
- type = getApparentTypeOfTypeParameter(<TypeParameter>type);
4478
- }
4479
- if (type.flags & TypeFlags.StringLike) {
4480
- type = globalStringType;
4481
- }
4482
- else if (type.flags & TypeFlags.NumberLike) {
4483
- type = globalNumberType;
4484
- }
4485
- else if (type.flags & TypeFlags.BooleanLike) {
4486
- type = globalBooleanType;
4487
- }
4488
- else if (type.flags & TypeFlags.ESSymbol) {
4489
- type = getGlobalESSymbolType();
4490
- }
4491
- return type;
4477
+ const t = type.flags & TypeFlags.TypeParameter ? getApparentTypeOfTypeParameter(<TypeParameter>type) : type;
4478
+ return t.flags & TypeFlags.StringLike ? globalStringType :
4479
+ t.flags & TypeFlags.NumberLike ? globalNumberType :
4480
+ t.flags & TypeFlags.BooleanLike ? globalBooleanType :
4481
+ t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType() :
4482
+ t.flags & TypeFlags.Index ? stringOrNumberType :
4483
+ t;
4492
4484
}
4493
4485
4494
4486
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string): Symbol {
@@ -5674,10 +5666,6 @@ namespace ts {
5674
5666
return links.resolvedType;
5675
5667
}
5676
5668
5677
- function getLiteralTypeFromPropertyName(prop: Symbol) {
5678
- return startsWith(prop.name, "__@") ? neverType : getLiteralTypeForText(TypeFlags.StringLiteral, unescapeIdentifier(prop.name));
5679
- }
5680
-
5681
5669
function getIndexTypeForTypeParameter(type: TypeParameter) {
5682
5670
if (!type.resolvedIndexType) {
5683
5671
type.resolvedIndexType = <IndexType>createType(TypeFlags.Index);
@@ -5686,10 +5674,19 @@ namespace ts {
5686
5674
return type.resolvedIndexType;
5687
5675
}
5688
5676
5677
+ function getLiteralTypeFromPropertyName(prop: Symbol) {
5678
+ return startsWith(prop.name, "__@") ? neverType : getLiteralTypeForText(TypeFlags.StringLiteral, unescapeIdentifier(prop.name));
5679
+ }
5680
+
5681
+ function getLiteralTypeFromPropertyNames(type: Type) {
5682
+ return getUnionType(map(getPropertiesOfType(type), getLiteralTypeFromPropertyName));
5683
+ }
5684
+
5689
5685
function getIndexType(type: Type): Type {
5690
- return type.flags & TypeFlags.TypeParameter ?
5691
- getIndexTypeForTypeParameter(<TypeParameter>type) :
5692
- getUnionType(map(getPropertiesOfType(type), getLiteralTypeFromPropertyName));
5686
+ return type.flags & TypeFlags.TypeParameter ? getIndexTypeForTypeParameter(<TypeParameter>type) :
5687
+ getIndexInfoOfType(type, IndexKind.String) ? stringOrNumberType :
5688
+ getIndexInfoOfType(type, IndexKind.Number) ? getUnionType([numberType, getLiteralTypeFromPropertyNames(type)]) :
5689
+ getLiteralTypeFromPropertyNames(type);
5693
5690
}
5694
5691
5695
5692
function getTypeFromTypeOperatorNode(node: TypeOperatorNode) {
@@ -5712,33 +5709,45 @@ namespace ts {
5712
5709
return indexedAccessTypes[objectType.id] || (indexedAccessTypes[objectType.id] = createIndexedAccessType(objectType, keyType));
5713
5710
}
5714
5711
5712
+ function getPropertyTypeForIndexType(objectType: Type, indexType: Type) {
5713
+ return indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral) && getTypeOfPropertyOfType(objectType, escapeIdentifier((<LiteralType>indexType).text)) ||
5714
+ isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.NumberLike) && getIndexTypeOfType(objectType, IndexKind.Number) ||
5715
+ isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike) && getIndexTypeOfType(objectType, IndexKind.String) ||
5716
+ undefined;
5717
+ }
5718
+
5715
5719
function getIndexedAccessType(objectType: Type, keyType: Type) {
5716
- if (keyType.flags & TypeFlags.TypeParameter) {
5717
- return getIndexedAccessTypeForTypeParameter(objectType, <TypeParameter>keyType);
5718
- }
5719
- if (isTypeOfKind(keyType, TypeFlags.StringLiteral) && !(keyType.flags & TypeFlags.Intersection)) {
5720
- return mapType(keyType, t => getTypeOfPropertyOfType(objectType, escapeIdentifier((<LiteralType>t).text)) || unknownType);
5721
- }
5722
- return keyType.flags & TypeFlags.Any ? anyType : unknownType;
5720
+ return keyType.flags & TypeFlags.Any ? anyType :
5721
+ keyType.flags & TypeFlags.TypeParameter ? getIndexedAccessTypeForTypeParameter(objectType, <TypeParameter>keyType) :
5722
+ mapType(keyType, t => getPropertyTypeForIndexType(objectType, t) || unknownType);
5723
5723
}
5724
5724
5725
5725
function resolveIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
5726
5726
const objectType = getTypeFromTypeNodeNoAlias(node.objectType);
5727
- const keyType = getTypeFromTypeNodeNoAlias(node.indexType);
5728
- if (keyType.flags & TypeFlags.TypeParameter &&
5729
- getConstraintOfTypeParameter(<TypeParameter>keyType) === getIndexType(objectType)) {
5730
- return getIndexedAccessType(objectType, keyType);
5731
- }
5732
- if (isTypeOfKind(keyType, TypeFlags.StringLiteral) && !(keyType.flags & TypeFlags.Intersection)) {
5733
- const missing = forEachType(keyType, t => getTypeOfPropertyOfType(objectType, escapeIdentifier((<LiteralType>t).text)) ? undefined : (<LiteralType>t).text);
5734
- if (missing) {
5735
- error(node.indexType, Diagnostics.Property_0_is_missing_in_type_1, missing, typeToString(objectType));
5727
+ const indexType = getTypeFromTypeNodeNoAlias(node.indexType);
5728
+ if (indexType.flags & TypeFlags.TypeParameter) {
5729
+ if (!isTypeAssignableTo(getConstraintOfTypeParameter(<TypeParameter>indexType), getIndexType(objectType))) {
5730
+ error(node.indexType, Diagnostics.Type_0_is_not_constrained_to_keyof_1, typeToString(indexType), typeToString(objectType));
5736
5731
return unknownType;
5737
5732
}
5738
- return getIndexedAccessType(objectType, keyType );
5733
+ return getIndexedAccessType(objectType, indexType );
5739
5734
}
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));
5741
- return unknownType;
5735
+ const indexTypes = indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Primitive) ? (<UnionType>indexType).types : [indexType];
5736
+ for (const t of indexTypes) {
5737
+ if (!getPropertyTypeForIndexType(objectType, t)) {
5738
+ if (t.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
5739
+ error(node.indexType, Diagnostics.Property_0_does_not_exist_on_type_1, (<LiteralType>t).text, typeToString(objectType))
5740
+ }
5741
+ else if (t.flags & (TypeFlags.String | TypeFlags.Number)) {
5742
+ error(node.indexType, Diagnostics.Type_0_has_no_matching_index_signature_for_type_1, typeToString(objectType), typeToString(t));
5743
+ }
5744
+ else {
5745
+ error(node.indexType, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(t));
5746
+ }
5747
+ return unknownType;
5748
+ }
5749
+ }
5750
+ return getIndexedAccessType(objectType, indexType);
5742
5751
}
5743
5752
5744
5753
function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
@@ -8606,10 +8615,6 @@ namespace ts {
8606
8615
return containsType(target.types, source);
8607
8616
}
8608
8617
8609
- function forEachType<T>(type: Type, f: (t: Type) => T): T {
8610
- return type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, f) : f(type);
8611
- }
8612
-
8613
8618
function filterType(type: Type, f: (t: Type) => boolean): Type {
8614
8619
if (type.flags & TypeFlags.Union) {
8615
8620
const types = (<UnionType>type).types;
0 commit comments