diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f9ab74b053256..02d585e53bb68 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18514,10 +18514,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!(getUnionType([intersectTypes(type1, type2), neverType]).flags & TypeFlags.Never); } + function hasOptionalModifiersProperty(mappedType: MappedType) { + const modifiersType = getApparentType(getModifiersTypeFromMappedType(mappedType)); + if (!(modifiersType.flags & TypeFlags.Object)) { + return false; + } + const properties = resolveStructuredTypeMembers(modifiersType as ObjectType).properties; + return some(properties, p => !!(p.flags & SymbolFlags.Optional)); + } + function substituteIndexedMappedType(objectType: MappedType, index: Type) { const mapper = createTypeMapper([getTypeParameterFromMappedType(objectType)], [index]); const templateMapper = combineTypeMappers(objectType.mapper, mapper); - return instantiateType(getTemplateTypeFromMappedType(objectType.target as MappedType || objectType), templateMapper); + const type = instantiateType(getTemplateTypeFromMappedType(objectType.target as MappedType || objectType), templateMapper); + return addOptionality(type, /*isProperty*/ true, hasOptionalModifiersProperty(objectType)); } function getIndexedAccessType(objectType: Type, indexType: Type, accessFlags = AccessFlags.None, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt b/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt index 472421be8dca5..d0f2b5bed2a2c 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt +++ b/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt @@ -31,9 +31,10 @@ keyofAndIndexedAccess2.ts(68,3): error TS2322: Type 'number' is not assignable t 'number' is assignable to the constraint of type 'T[K]', but 'T[K]' could be instantiated with a different subtype of constraint 'number'. keyofAndIndexedAccess2.ts(108,5): error TS2322: Type '123' is not assignable to type 'Type[K]'. Type 'number' is not assignable to type 'never'. +keyofAndIndexedAccess2.ts(115,21): error TS2313: Type parameter 'Q' has a circular constraint. -==== keyofAndIndexedAccess2.ts (23 errors) ==== +==== keyofAndIndexedAccess2.ts (24 errors) ==== function f1(obj: { a: number, b: 0 | 1, c: string }, k0: 'a', k1: 'a' | 'b', k2: 'a' | 'b' | 'c') { obj[k0] = 1; obj[k0] = 2; @@ -205,6 +206,9 @@ keyofAndIndexedAccess2.ts(108,5): error TS2322: Type '123' is not assignable to type StrictExtract = T extends U ? U extends T ? T : never : never; type StrictExclude = T extends StrictExtract ? never : T; type A = { [Q in { [P in keyof T]: P; }[keyof T]]: T[Q]; }; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2313: Type parameter 'Q' has a circular constraint. +!!! related TS2751 keyofAndIndexedAccess2.ts:116:36: Circularity originates in type at this location. type B = A<{ [Q in keyof T]: StrictExclude, {}>; }>; // Repros from #30938