diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 80b61edd3657a..bebbe7ababa7f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12337,7 +12337,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getNonMissingTypeOfSymbol(symbol: Symbol) { - return removeMissingType(getTypeOfSymbol(symbol), !!(symbol.flags & SymbolFlags.Optional)); + let type = getTypeOfSymbol(symbol); + if (exactOptionalPropertyTypes) { + const checkFlags = getCheckFlags(symbol); + if (checkFlags & CheckFlags.Mapped) { + const mappedType = (symbol as MappedSymbol).links.mappedType; + const keyType = (symbol as MappedSymbol).links.keyType; + const modifiersType = getModifiersTypeFromMappedType(mappedType); + if (modifiersType !== unknownType) { + type = mapType(type, t => { + if (!(t.flags & TypeFlags.IndexedAccess) || (t as IndexedAccessType).objectType !== modifiersType || (t as IndexedAccessType).indexType !== keyType) { + return t; + } + return getIndexedAccessType(modifiersType, keyType, AccessFlags.NonMissing, /*accessNode*/ undefined, t.aliasSymbol, t.aliasTypeArguments); + }); + } + } + } + return removeMissingType(type, !!(symbol.flags & SymbolFlags.Optional)); } function isReferenceToSomeType(type: Type, targets: readonly Type[]) { @@ -18630,7 +18647,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return autoType; } } - const propType = accessFlags & AccessFlags.Writing ? getWriteTypeOfSymbol(prop) : getTypeOfSymbol(prop); + const propType = accessFlags & AccessFlags.Writing ? + getWriteTypeOfSymbol(prop) : + removeMissingType(getTypeOfSymbol(prop), !!(prop.flags & SymbolFlags.Optional && accessFlags & AccessFlags.NonMissing)); return accessExpression && getAssignmentTargetKind(accessExpression) !== AssignmentKind.Definite ? getFlowTypeOfReference(accessExpression, propType) : accessNode && isIndexedAccessTypeNode(accessNode) && containsMissingType(propType) ? getUnionType([propType, undefinedType]) : propType; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 49938f0fc8249..2b8367986ad3b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6835,11 +6835,12 @@ export const enum AccessFlags { Writing = 1 << 2, CacheSymbol = 1 << 3, AllowMissing = 1 << 4, - ExpressionPosition = 1 << 5, - ReportDeprecated = 1 << 6, - SuppressNoImplicitAnyError = 1 << 7, - Contextual = 1 << 8, - Persistent = IncludeUndefined, + NonMissing = 1 << 5, + ExpressionPosition = 1 << 6, + ReportDeprecated = 1 << 7, + SuppressNoImplicitAnyError = 1 << 8, + Contextual = 1 << 9, + Persistent = IncludeUndefined | NonMissing, } // Indexed access types (TypeFlags.IndexedAccess) diff --git a/tests/baselines/reference/mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.symbols b/tests/baselines/reference/mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.symbols new file mode 100644 index 0000000000000..b68d58f4192cb --- /dev/null +++ b/tests/baselines/reference/mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.symbols @@ -0,0 +1,91 @@ +//// [tests/cases/compiler/mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts] //// + +=== mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts === +// https://github.com/microsoft/TypeScript/issues/60233 + +type T = { +>T : Symbol(T, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 0, 0)) + + foo?: true; +>foo : Symbol(foo, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 2, 10)) + + bar?: true; +>bar : Symbol(bar, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 3, 13)) + +}; + +type WrappedT = [t]; +>WrappedT : Symbol(WrappedT, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 5, 2)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 7, 14)) +>T : Symbol(T, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 0, 0)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 7, 14)) + +type OmitBarFromWrapped = t extends WrappedT +>OmitBarFromWrapped : Symbol(OmitBarFromWrapped, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 7, 33)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 9, 24)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 9, 24)) +>WrappedT : Symbol(WrappedT, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 5, 2)) +>inner : Symbol(inner, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 9, 53)) + + ? WrappedT> +>WrappedT : Symbol(WrappedT, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 5, 2)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>inner : Symbol(inner, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 9, 53)) + + : never; + +type OmitHomomorphicFromWrapped = t extends WrappedT +>OmitHomomorphicFromWrapped : Symbol(OmitHomomorphicFromWrapped, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 11, 10)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 13, 32)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 13, 32)) +>WrappedT : Symbol(WrappedT, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 5, 2)) +>inner : Symbol(inner, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 13, 61)) + + ? WrappedT> +>WrappedT : Symbol(WrappedT, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 5, 2)) +>HomomorphicOmit : Symbol(HomomorphicOmit, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 15, 10)) +>inner : Symbol(inner, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 13, 61)) + + : never; + +type HomomorphicOmit = { +>HomomorphicOmit : Symbol(HomomorphicOmit, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 15, 10)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 17, 21)) +>keyToOmit : Symbol(keyToOmit, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 17, 23)) + + [k in keyof t as k extends keyToOmit ? never : k]: t[k]; +>k : Symbol(k, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 18, 3)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 17, 21)) +>k : Symbol(k, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 18, 3)) +>keyToOmit : Symbol(keyToOmit, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 17, 23)) +>k : Symbol(k, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 18, 3)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 17, 21)) +>k : Symbol(k, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 18, 3)) + +}; + +type OmitHomomorphicFromWrappedConformed = t extends WrappedT +>OmitHomomorphicFromWrappedConformed : Symbol(OmitHomomorphicFromWrappedConformed, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 19, 2)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 21, 41)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 21, 41)) +>WrappedT : Symbol(WrappedT, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 5, 2)) +>inner : Symbol(inner, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 21, 70)) + + ? WrappedT, T>> +>WrappedT : Symbol(WrappedT, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 5, 2)) +>conform : Symbol(conform, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 23, 10)) +>HomomorphicOmit : Symbol(HomomorphicOmit, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 15, 10)) +>inner : Symbol(inner, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 21, 70)) +>T : Symbol(T, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 0, 0)) + + : never; + +type conform = t extends base ? t : base; +>conform : Symbol(conform, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 23, 10)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 25, 13)) +>base : Symbol(base, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 25, 15)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 25, 13)) +>base : Symbol(base, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 25, 15)) +>t : Symbol(t, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 25, 13)) +>base : Symbol(base, Decl(mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts, 25, 15)) + diff --git a/tests/baselines/reference/mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.types b/tests/baselines/reference/mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.types new file mode 100644 index 0000000000000..8dcf2af15bd46 --- /dev/null +++ b/tests/baselines/reference/mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.types @@ -0,0 +1,59 @@ +//// [tests/cases/compiler/mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts] //// + +=== mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts === +// https://github.com/microsoft/TypeScript/issues/60233 + +type T = { +>T : T +> : ^ + + foo?: true; +>foo : true | undefined +> : ^^^^^^^^^^^^^^^^ +>true : true +> : ^^^^ + + bar?: true; +>bar : true | undefined +> : ^^^^^^^^^^^^^^^^ +>true : true +> : ^^^^ + +}; + +type WrappedT = [t]; +>WrappedT : WrappedT +> : ^^^^^^^^^^^ + +type OmitBarFromWrapped = t extends WrappedT +>OmitBarFromWrapped : OmitBarFromWrapped +> : ^^^^^^^^^^^^^^^^^^^^^ + + ? WrappedT> + : never; + +type OmitHomomorphicFromWrapped = t extends WrappedT +>OmitHomomorphicFromWrapped : OmitHomomorphicFromWrapped +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ? WrappedT> + : never; + +type HomomorphicOmit = { +>HomomorphicOmit : HomomorphicOmit +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + [k in keyof t as k extends keyToOmit ? never : k]: t[k]; +}; + +type OmitHomomorphicFromWrappedConformed = t extends WrappedT +>OmitHomomorphicFromWrappedConformed : OmitHomomorphicFromWrappedConformed +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ? WrappedT, T>> + : never; + +type conform = t extends base ? t : base; +>conform : conform +> : ^^^^^^^^^^^^^^^^ + diff --git a/tests/cases/compiler/mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts b/tests/cases/compiler/mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts new file mode 100644 index 0000000000000..099f79a242afb --- /dev/null +++ b/tests/cases/compiler/mappedTypeConstraintAssignabilityExactOptionalPropertyTypes1.ts @@ -0,0 +1,30 @@ +// @strict: true +// @exactOptionalPropertyTypes: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/60233 + +type T = { + foo?: true; + bar?: true; +}; + +type WrappedT = [t]; + +type OmitBarFromWrapped = t extends WrappedT + ? WrappedT> + : never; + +type OmitHomomorphicFromWrapped = t extends WrappedT + ? WrappedT> + : never; + +type HomomorphicOmit = { + [k in keyof t as k extends keyToOmit ? never : k]: t[k]; +}; + +type OmitHomomorphicFromWrappedConformed = t extends WrappedT + ? WrappedT, T>> + : never; + +type conform = t extends base ? t : base;