@@ -6268,18 +6268,10 @@ namespace ts {
6268
6268
}
6269
6269
6270
6270
function getConstraintOfIndexedAccess(type: IndexedAccessType) {
6271
- const transformed = getSimplifiedIndexedAccessType(type);
6272
- if (transformed) {
6273
- return transformed;
6274
- }
6275
- const baseObjectType = getBaseConstraintOfType(type.objectType);
6276
- const baseIndexType = getBaseConstraintOfType(type.indexType);
6277
- if (baseIndexType === stringType && !getIndexInfoOfType(baseObjectType || type.objectType, IndexKind.String)) {
6278
- // getIndexedAccessType returns `any` for X[string] where X doesn't have an index signature.
6279
- // to avoid this, return `undefined`.
6280
- return undefined;
6281
- }
6282
- return baseObjectType || baseIndexType ? getIndexedAccessType(baseObjectType || type.objectType, baseIndexType || type.indexType) : undefined;
6271
+ const objectType = getBaseConstraintOfType(type.objectType) || type.objectType;
6272
+ const indexType = getBaseConstraintOfType(type.indexType) || type.indexType;
6273
+ const constraint = !isGenericObjectType(objectType) && !isGenericIndexType(indexType) ? getIndexedAccessType(objectType, indexType) : undefined;
6274
+ return constraint && constraint !== unknownType ? constraint : undefined;
6283
6275
}
6284
6276
6285
6277
function getDefaultConstraintOfConditionalType(type: ConditionalType) {
@@ -6326,7 +6318,7 @@ namespace ts {
6326
6318
function getBaseConstraintOfType(type: Type): Type {
6327
6319
const constraint = getBaseConstraintOfInstantiableNonPrimitiveUnionOrIntersection(type);
6328
6320
if (!constraint && type.flags & TypeFlags.Index) {
6329
- return stringType ;
6321
+ return keyofConstraintType ;
6330
6322
}
6331
6323
return constraint;
6332
6324
}
@@ -6361,7 +6353,7 @@ namespace ts {
6361
6353
circular = true;
6362
6354
return undefined;
6363
6355
}
6364
- const result = computeBaseConstraint(t );
6356
+ const result = computeBaseConstraint(getSimplifiedType(t) );
6365
6357
if (!popTypeResolution()) {
6366
6358
circular = true;
6367
6359
return undefined;
@@ -6390,13 +6382,9 @@ namespace ts {
6390
6382
undefined;
6391
6383
}
6392
6384
if (t.flags & TypeFlags.Index) {
6393
- return stringType ;
6385
+ return keyofConstraintType ;
6394
6386
}
6395
6387
if (t.flags & TypeFlags.IndexedAccess) {
6396
- const transformed = getSimplifiedIndexedAccessType(<IndexedAccessType>t);
6397
- if (transformed) {
6398
- return getBaseConstraint(transformed);
6399
- }
6400
6388
const baseObjectType = getBaseConstraint((<IndexedAccessType>t).objectType);
6401
6389
const baseIndexType = getBaseConstraint((<IndexedAccessType>t).indexType);
6402
6390
const baseIndexedAccess = baseObjectType && baseIndexType ? getIndexedAccessType(baseObjectType, baseIndexType) : undefined;
@@ -6520,26 +6508,30 @@ namespace ts {
6520
6508
if (props.length === 1 && !(checkFlags & CheckFlags.Partial)) {
6521
6509
return props[0];
6522
6510
}
6523
- const propTypes: Type[] = [];
6524
- const declarations: Declaration[] = [];
6511
+ let declarations: Declaration[];
6525
6512
let commonType: Type;
6513
+ let nameType: Type;
6514
+ let propTypes: Type[] = [];
6515
+ let first = true;
6526
6516
for (const prop of props) {
6527
- if (prop.declarations) {
6528
- addRange(declarations, prop.declarations);
6529
- }
6517
+ declarations = addRange(declarations, prop.declarations);
6530
6518
const type = getTypeOfSymbol(prop);
6531
- if (!commonType ) {
6519
+ if (first ) {
6532
6520
commonType = type;
6521
+ nameType = prop.nameType;
6522
+ first = false;
6533
6523
}
6534
- else if (type !== commonType) {
6524
+ else {
6525
+ if (type !== commonType) {
6535
6526
checkFlags |= CheckFlags.HasNonUniformType;
6536
6527
}
6528
+ }
6537
6529
propTypes.push(type);
6538
6530
}
6539
- // !!!
6540
6531
const result = createSymbol(SymbolFlags.Property | commonFlags, name, syntheticFlag | checkFlags);
6541
6532
result.containingType = containingType;
6542
6533
result.declarations = declarations;
6534
+ result.nameType = nameType;
6543
6535
result.type = isUnion ? getUnionType(propTypes) : getIntersectionType(propTypes);
6544
6536
return result;
6545
6537
}
@@ -8151,9 +8143,8 @@ namespace ts {
8151
8143
maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type) :
8152
8144
getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(<MappedType>type) :
8153
8145
type === wildcardType ? wildcardType :
8154
- type.flags & TypeFlags.Any ? keyofConstraintType :
8155
- keyofStringsOnly ? getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromPropertyNames(type, TypeFlags.StringLiteral) :
8156
- getIndexInfoOfType(type, IndexKind.String) ? getUnionType([stringType, numberType, getLiteralTypeFromPropertyNames(type, TypeFlags.UniqueESSymbol)]) :
8146
+ type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? keyofConstraintType :
8147
+ keyofStringsOnly ? getLiteralTypeFromPropertyNames(type, TypeFlags.StringLiteral) :
8157
8148
getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromPropertyNames(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) :
8158
8149
getLiteralTypeFromPropertyNames(type, TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.UniqueESSymbol);
8159
8150
}
@@ -8256,9 +8247,8 @@ namespace ts {
8256
8247
else {
8257
8248
error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType));
8258
8249
}
8259
- return unknownType;
8260
8250
}
8261
- return anyType ;
8251
+ return unknownType ;
8262
8252
}
8263
8253
8264
8254
function isGenericObjectType(type: Type): boolean {
@@ -8285,8 +8275,12 @@ namespace ts {
8285
8275
return getObjectFlags(type) & ObjectFlags.Mapped && getTemplateTypeFromMappedType(type as MappedType) === neverType;
8286
8276
}
8287
8277
8278
+ function getSimplifiedType(type: Type): Type {
8279
+ return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(<IndexedAccessType>type) : type;
8280
+ }
8281
+
8288
8282
// Transform an indexed access to a simpler form, if possible. Return the simpler form, or return
8289
- // undefined if no transformation is possible.
8283
+ // the type itself if no transformation is possible.
8290
8284
function getSimplifiedIndexedAccessType(type: IndexedAccessType): Type {
8291
8285
const objectType = type.objectType;
8292
8286
if (objectType.flags & TypeFlags.Intersection && isGenericObjectType(objectType)) {
@@ -8306,7 +8300,7 @@ namespace ts {
8306
8300
}
8307
8301
}
8308
8302
return getUnionType([
8309
- getIndexedAccessType(getIntersectionType(regularTypes), type.indexType),
8303
+ getSimplifiedType( getIndexedAccessType(getIntersectionType(regularTypes), type.indexType) ),
8310
8304
getIntersectionType(stringIndexTypes)
8311
8305
]);
8312
8306
}
@@ -8316,13 +8310,13 @@ namespace ts {
8316
8310
// eventually anyway, but it easier to reason about.
8317
8311
if (some((<IntersectionType>objectType).types, isMappedTypeToNever)) {
8318
8312
const nonNeverTypes = filter((<IntersectionType>objectType).types, t => !isMappedTypeToNever(t));
8319
- return getIndexedAccessType(getIntersectionType(nonNeverTypes), type.indexType);
8313
+ return getSimplifiedType( getIndexedAccessType(getIntersectionType(nonNeverTypes), type.indexType) );
8320
8314
}
8321
8315
}
8322
-
8323
8316
// If the object type is a mapped type { [P in K]: E }, where K is generic, instantiate E using a mapper
8324
8317
// that substitutes the index type for P. For example, for an index access { [P in K]: Box<T[P]> }[X], we
8325
- // construct the type Box<T[X]>.
8318
+ // construct the type Box<T[X]>. We do not further simplify the result because mapped types can be recursive
8319
+ // and we might never terminate.
8326
8320
if (isGenericMappedType(objectType)) {
8327
8321
return substituteIndexedMappedType(objectType, type);
8328
8322
}
@@ -8332,7 +8326,7 @@ namespace ts {
8332
8326
return substituteIndexedMappedType(constraint, type);
8333
8327
}
8334
8328
}
8335
- return undefined ;
8329
+ return type ;
8336
8330
}
8337
8331
8338
8332
function substituteIndexedMappedType(objectType: MappedType, type: IndexedAccessType) {
@@ -9887,6 +9881,12 @@ namespace ts {
9887
9881
if (target.flags & TypeFlags.Substitution) {
9888
9882
target = (<SubstitutionType>target).typeVariable;
9889
9883
}
9884
+ if (source.flags & TypeFlags.IndexedAccess) {
9885
+ source = getSimplifiedType(source);
9886
+ }
9887
+ if (target.flags & TypeFlags.IndexedAccess) {
9888
+ target = getSimplifiedType(target);
9889
+ }
9890
9890
9891
9891
// both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases
9892
9892
if (source === target) return Ternary.True;
@@ -10346,9 +10346,9 @@ namespace ts {
10346
10346
}
10347
10347
}
10348
10348
else if (target.flags & TypeFlags.IndexedAccess) {
10349
- // A type S is related to a type T[K] if S is related to A[K] , where K is string-like and
10350
- // A is the apparent type of T.
10351
- const constraint = getConstraintForRelation(<IndexedAccessType> target);
10349
+ // A type S is related to a type T[K] if S is related to C , where C is the
10350
+ // constraint of T[K]
10351
+ const constraint = getConstraintForRelation(target);
10352
10352
if (constraint) {
10353
10353
if (result = isRelatedTo(source, constraint, reportErrors)) {
10354
10354
errorInfo = saveErrorInfo;
@@ -10361,21 +10361,21 @@ namespace ts {
10361
10361
const template = getTemplateTypeFromMappedType(target);
10362
10362
const modifiers = getMappedTypeModifiers(target);
10363
10363
if (!(modifiers & MappedTypeModifiers.ExcludeOptional)) {
10364
- if (template.flags & TypeFlags.IndexedAccess && (<IndexedAccessType>template).objectType === source &&
10365
- (<IndexedAccessType>template).indexType === getTypeParameterFromMappedType(target)) {
10366
- return Ternary.True;
10367
- }
10368
- // A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X.
10369
- if (!isGenericMappedType(source) && getConstraintTypeFromMappedType(target) === getIndexType(source)) {
10370
- const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target));
10371
- const templateType = getTemplateTypeFromMappedType(target);
10372
- if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) {
10373
- errorInfo = saveErrorInfo;
10374
- return result;
10364
+ if (template.flags & TypeFlags.IndexedAccess && (<IndexedAccessType>template).objectType === source &&
10365
+ (<IndexedAccessType>template).indexType === getTypeParameterFromMappedType(target)) {
10366
+ return Ternary.True;
10367
+ }
10368
+ // A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X.
10369
+ if (!isGenericMappedType(source) && getConstraintTypeFromMappedType(target) === getIndexType(source)) {
10370
+ const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target));
10371
+ const templateType = getTemplateTypeFromMappedType(target);
10372
+ if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) {
10373
+ errorInfo = saveErrorInfo;
10374
+ return result;
10375
+ }
10375
10376
}
10376
10377
}
10377
10378
}
10378
- }
10379
10379
10380
10380
if (source.flags & TypeFlags.TypeParameter) {
10381
10381
let constraint = getConstraintForRelation(<TypeParameter>source);
@@ -10393,16 +10393,8 @@ namespace ts {
10393
10393
}
10394
10394
}
10395
10395
else if (source.flags & TypeFlags.IndexedAccess) {
10396
- // A type S[K] is related to a type T if A[K] is related to T, where K is string-like and
10397
- // A is the apparent type of S.
10398
- const constraint = getConstraintForRelation(<IndexedAccessType>source);
10399
- if (constraint) {
10400
- if (result = isRelatedTo(constraint, target, reportErrors)) {
10401
- errorInfo = saveErrorInfo;
10402
- return result;
10403
- }
10404
- }
10405
- else if (target.flags & TypeFlags.IndexedAccess) {
10396
+ if (target.flags & TypeFlags.IndexedAccess) {
10397
+ // A type S[K] is related to a type T[J] if S is related to T and K is related to J.
10406
10398
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, reportErrors)) {
10407
10399
result &= isRelatedTo((<IndexedAccessType>source).indexType, (<IndexedAccessType>target).indexType, reportErrors);
10408
10400
}
@@ -10411,6 +10403,15 @@ namespace ts {
10411
10403
return result;
10412
10404
}
10413
10405
}
10406
+ // A type S[K] is related to a type T if C is related to T, where C is the
10407
+ // constraint of S[K].
10408
+ const constraint = getConstraintForRelation(<IndexedAccessType>source);
10409
+ if (constraint) {
10410
+ if (result = isRelatedTo(constraint, target, reportErrors)) {
10411
+ errorInfo = saveErrorInfo;
10412
+ return result;
10413
+ }
10414
+ }
10414
10415
}
10415
10416
else if (source.flags & TypeFlags.Index) {
10416
10417
if (result = isRelatedTo(keyofConstraintType, target, reportErrors)) {
@@ -19917,7 +19918,8 @@ namespace ts {
19917
19918
// this a literal context for literals of that primitive type. For example, given a
19918
19919
// type parameter 'T extends string', infer string literal types for T.
19919
19920
const constraint = getBaseConstraintOfType(contextualType) || emptyObjectType;
19920
- return constraint.flags & TypeFlags.String && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) ||
19921
+ return constraint === keyofConstraintType && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.UniqueESSymbol) ||
19922
+ constraint.flags & TypeFlags.String && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) ||
19921
19923
constraint.flags & TypeFlags.Number && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) ||
19922
19924
constraint.flags & TypeFlags.Boolean && maybeTypeOfKind(candidateType, TypeFlags.BooleanLiteral) ||
19923
19925
constraint.flags & TypeFlags.ESSymbol && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol) ||
0 commit comments