@@ -7119,14 +7119,31 @@ namespace ts {
7119
7119
return !!(typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default));
7120
7120
}
7121
7121
7122
+ function getApparentTypeOfMappedType(type: MappedType) {
7123
+ return type.resolvedApparentType || (type.resolvedApparentType = getResolvedApparentTypeOfMappedType(type));
7124
+ }
7125
+
7126
+ function getResolvedApparentTypeOfMappedType(type: MappedType) {
7127
+ const typeVariable = getHomomorphicTypeVariable(type);
7128
+ if (typeVariable) {
7129
+ const constraint = getConstraintOfTypeParameter(typeVariable);
7130
+ if (constraint && (isArrayType(constraint) || isReadonlyArrayType(constraint) || isTupleType(constraint))) {
7131
+ const mapper = makeUnaryTypeMapper(typeVariable, constraint);
7132
+ return instantiateType(type, combineTypeMappers(mapper, type.mapper));
7133
+ }
7134
+ }
7135
+ return type;
7136
+ }
7137
+
7122
7138
/**
7123
7139
* For a type parameter, return the base constraint of the type parameter. For the string, number,
7124
7140
* boolean, and symbol primitive types, return the corresponding object types. Otherwise return the
7125
7141
* type itself. Note that the apparent type of a union type is the union type itself.
7126
7142
*/
7127
7143
function getApparentType(type: Type): Type {
7128
7144
const t = type.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(type) || emptyObjectType : type;
7129
- return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(<IntersectionType>t) :
7145
+ return getObjectFlags(t) & ObjectFlags.Mapped ? getApparentTypeOfMappedType(<MappedType>t) :
7146
+ t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(<IntersectionType>t) :
7130
7147
t.flags & TypeFlags.StringLike ? globalStringType :
7131
7148
t.flags & TypeFlags.NumberLike ? globalNumberType :
7132
7149
t.flags & TypeFlags.BooleanLike ? globalBooleanType :
@@ -10159,8 +10176,19 @@ namespace ts {
10159
10176
}
10160
10177
}
10161
10178
10179
+ function getHomomorphicTypeVariable(type: MappedType) {
10180
+ const constraintType = getConstraintTypeFromMappedType(type);
10181
+ if (constraintType.flags & TypeFlags.Index) {
10182
+ const typeVariable = (<IndexType>constraintType).type;
10183
+ if (typeVariable.flags & TypeFlags.TypeParameter) {
10184
+ return <TypeParameter>typeVariable;
10185
+ }
10186
+ }
10187
+ return undefined;
10188
+ }
10189
+
10162
10190
function instantiateMappedType(type: MappedType, mapper: TypeMapper): Type {
10163
- // For a momomorphic mapped type { [P in keyof T]: X }, where T is some type variable, the mapping
10191
+ // For a homomorphic mapped type { [P in keyof T]: X }, where T is some type variable, the mapping
10164
10192
// operation depends on T as follows:
10165
10193
// * If T is a primitive type no mapping is performed and the result is simply T.
10166
10194
// * If T is a union type we distribute the mapped type over the union.
@@ -10170,32 +10198,25 @@ namespace ts {
10170
10198
// For example, when T is instantiated to a union type A | B, we produce { [P in keyof A]: X } |
10171
10199
// { [P in keyof B]: X }, and when when T is instantiated to a union type A | undefined, we produce
10172
10200
// { [P in keyof A]: X } | undefined.
10173
- const constraintType = getConstraintTypeFromMappedType(type);
10174
- if (constraintType.flags & TypeFlags.Index) {
10175
- const typeVariable = (<IndexType>constraintType).type;
10176
- if (typeVariable.flags & TypeFlags.TypeParameter) {
10177
- const mappedTypeVariable = instantiateType(typeVariable, mapper);
10178
- if (typeVariable !== mappedTypeVariable) {
10179
- return mapType(mappedTypeVariable, t => {
10180
- if (isMappableType(t)) {
10181
- const replacementMapper = createReplacementMapper(typeVariable, t, mapper);
10182
- return isArrayType(t) ? createArrayType(instantiateMappedTypeTemplate(type, numberType, /*isOptional*/ true, replacementMapper)) :
10183
- isReadonlyArrayType(t) ? createReadonlyArrayType(instantiateMappedTypeTemplate(type, numberType, /*isOptional*/ true, replacementMapper)) :
10184
- isTupleType(t) ? instantiateMappedTupleType(t, type, replacementMapper) :
10185
- instantiateAnonymousType(type, replacementMapper);
10186
- }
10187
- return t;
10188
- });
10189
- }
10201
+ const typeVariable = getHomomorphicTypeVariable(type);
10202
+ if (typeVariable) {
10203
+ const mappedTypeVariable = instantiateType(typeVariable, mapper);
10204
+ if (typeVariable !== mappedTypeVariable) {
10205
+ return mapType(mappedTypeVariable, t => {
10206
+ if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType) {
10207
+ const replacementMapper = createReplacementMapper(typeVariable, t, mapper);
10208
+ return isArrayType(t) ? createArrayType(instantiateMappedTypeTemplate(type, numberType, /*isOptional*/ true, replacementMapper)) :
10209
+ isReadonlyArrayType(t) ? createReadonlyArrayType(instantiateMappedTypeTemplate(type, numberType, /*isOptional*/ true, replacementMapper)) :
10210
+ isTupleType(t) ? instantiateMappedTupleType(t, type, replacementMapper) :
10211
+ instantiateAnonymousType(type, replacementMapper);
10212
+ }
10213
+ return t;
10214
+ });
10190
10215
}
10191
10216
}
10192
10217
return instantiateAnonymousType(type, mapper);
10193
10218
}
10194
10219
10195
- function isMappableType(type: Type) {
10196
- return type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection);
10197
- }
10198
-
10199
10220
function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, mapper: TypeMapper) {
10200
10221
const minLength = tupleType.target.minLength;
10201
10222
const elementTypes = map(tupleType.typeArguments || emptyArray, (_, i) =>
@@ -11623,7 +11644,6 @@ namespace ts {
11623
11644
const constraint = getConstraintForRelation(target);
11624
11645
if (constraint) {
11625
11646
if (result = isRelatedTo(source, constraint, reportErrors)) {
11626
- errorInfo = saveErrorInfo;
11627
11647
return result;
11628
11648
}
11629
11649
}
@@ -11642,7 +11662,6 @@ namespace ts {
11642
11662
const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target));
11643
11663
const templateType = getTemplateTypeFromMappedType(target);
11644
11664
if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) {
11645
- errorInfo = saveErrorInfo;
11646
11665
return result;
11647
11666
}
11648
11667
}
@@ -11716,6 +11735,23 @@ namespace ts {
11716
11735
}
11717
11736
}
11718
11737
else {
11738
+ // An empty object type is related to any mapped type that includes a '?' modifier.
11739
+ if (isPartialMappedType(target) && !isGenericMappedType(source) && isEmptyObjectType(source)) {
11740
+ return Ternary.True;
11741
+ }
11742
+ if (isGenericMappedType(target)) {
11743
+ if (isGenericMappedType(source)) {
11744
+ if (result = mappedTypeRelatedTo(source, target, reportErrors)) {
11745
+ errorInfo = saveErrorInfo;
11746
+ return result;
11747
+ }
11748
+ }
11749
+ return Ternary.False;
11750
+ }
11751
+ const sourceIsPrimitive = !!(source.flags & TypeFlags.Primitive);
11752
+ if (relation !== identityRelation) {
11753
+ source = getApparentType(source);
11754
+ }
11719
11755
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target &&
11720
11756
!(getObjectFlags(source) & ObjectFlags.MarkerType || getObjectFlags(target) & ObjectFlags.MarkerType)) {
11721
11757
// We have type references to the same generic type, and the type references are not marker
@@ -11751,34 +11787,21 @@ namespace ts {
11751
11787
}
11752
11788
// Even if relationship doesn't hold for unions, intersections, or generic type references,
11753
11789
// it may hold in a structural comparison.
11754
- const sourceIsPrimitive = !!(source.flags & TypeFlags.Primitive);
11755
- if (relation !== identityRelation) {
11756
- source = getApparentType(source);
11757
- }
11758
11790
// In a check of the form X = A & B, we will have previously checked if A relates to X or B relates
11759
11791
// to X. Failing both of those we want to check if the aggregation of A and B's members structurally
11760
11792
// relates to X. Thus, we include intersection types on the source side here.
11761
11793
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection) && target.flags & TypeFlags.Object) {
11762
11794
// Report structural errors only if we haven't reported any errors yet
11763
11795
const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo && !sourceIsPrimitive;
11764
- // An empty object type is related to any mapped type that includes a '?' modifier.
11765
- if (isPartialMappedType(target) && !isGenericMappedType(source) && isEmptyObjectType(source)) {
11766
- result = Ternary.True;
11767
- }
11768
- else if (isGenericMappedType(target)) {
11769
- result = isGenericMappedType(source) ? mappedTypeRelatedTo(source, target, reportStructuralErrors) : Ternary.False;
11770
- }
11771
- else {
11772
- result = propertiesRelatedTo(source, target, reportStructuralErrors);
11796
+ result = propertiesRelatedTo(source, target, reportStructuralErrors);
11797
+ if (result) {
11798
+ result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportStructuralErrors);
11773
11799
if (result) {
11774
- result &= signaturesRelatedTo(source, target, SignatureKind.Call , reportStructuralErrors);
11800
+ result &= signaturesRelatedTo(source, target, SignatureKind.Construct , reportStructuralErrors);
11775
11801
if (result) {
11776
- result &= signaturesRelatedTo (source, target, SignatureKind.Construct , reportStructuralErrors);
11802
+ result &= indexTypesRelatedTo (source, target, IndexKind.String, sourceIsPrimitive , reportStructuralErrors);
11777
11803
if (result) {
11778
- result &= indexTypesRelatedTo(source, target, IndexKind.String, sourceIsPrimitive, reportStructuralErrors);
11779
- if (result) {
11780
- result &= indexTypesRelatedTo(source, target, IndexKind.Number, sourceIsPrimitive, reportStructuralErrors);
11781
- }
11804
+ result &= indexTypesRelatedTo(source, target, IndexKind.Number, sourceIsPrimitive, reportStructuralErrors);
11782
11805
}
11783
11806
}
11784
11807
}
0 commit comments