diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 480f7189fce31..9bcfa8d76a664 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23701,8 +23701,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Check if source type `S` is related to target type `{ [P in Q]: T }` or `{ [P in Q as R]: T}`. const keysRemapped = !!target.declaration.nameType; const templateType = getTemplateTypeFromMappedType(target); - const modifiers = getMappedTypeModifiers(target); - if (!(modifiers & MappedTypeModifiers.ExcludeOptional)) { + const combinedOptionality = getCombinedMappedTypeOptionality(target); + if (combinedOptionality !== -1) { // If the mapped type has shape `{ [P in Q]: T[P] }`, // source `S` is related to target if `T` = `S`, i.e. `S` is related to `{ [P in Q]: S[P] }`. if ( @@ -23717,7 +23717,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetKeys = keysRemapped ? getNameTypeFromMappedType(target)! : getConstraintTypeFromMappedType(target); // Type of the keys of source type `S`, i.e. `keyof S`. const sourceKeys = getIndexType(source, IndexFlags.NoIndexSignatures); - const includeOptional = modifiers & MappedTypeModifiers.IncludeOptional; + const includeOptional = combinedOptionality === 1; const filteredByApplicability = includeOptional ? intersectTypes(targetKeys, sourceKeys) : undefined; // A source type `S` is related to a target type `{ [P in Q]: T }` if `Q` is related to `keyof S` and `S[Q]` is related to `T`. // A source type `S` is related to a target type `{ [P in Q as R]: T }` if `R` is related to `keyof S` and `S[R]` is related to `T. @@ -23734,10 +23734,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Fastpath: When the template type has the form `Obj[P]` where `P` is the mapped type parameter, directly compare source `S` with `Obj` // to avoid creating the (potentially very large) number of new intermediate types made by manufacturing `S[P]`. const nonNullComponent = extractTypesOfKind(templateType, ~TypeFlags.Nullable); - if (!keysRemapped && nonNullComponent.flags & TypeFlags.IndexedAccess && (nonNullComponent as IndexedAccessType).indexType === typeParameter) { - if (result = isRelatedTo(source, (nonNullComponent as IndexedAccessType).objectType, RecursionFlags.Target, reportErrors)) { - return result; - } + if (!keysRemapped && nonNullComponent.flags & TypeFlags.IndexedAccess && (nonNullComponent as IndexedAccessType).indexType === typeParameter && (result = isRelatedTo(source, (nonNullComponent as IndexedAccessType).objectType, RecursionFlags.Target, reportErrors))) { + return result; } else { // We need to compare the type of a property on the source type `S` to the type of the same property on the target type, diff --git a/tests/baselines/reference/mappedTypeRelationships2.errors.txt b/tests/baselines/reference/mappedTypeRelationships2.errors.txt new file mode 100644 index 0000000000000..c82474fedece6 --- /dev/null +++ b/tests/baselines/reference/mappedTypeRelationships2.errors.txt @@ -0,0 +1,40 @@ +mappedTypeRelationships2.ts(21,38): error TS2344: Type 'ABC' does not satisfy the constraint 'WithNumber>'. + + +==== mappedTypeRelationships2.ts (1 errors) ==== + // https://github.com/microsoft/TypeScript/issues/62717 + + type Alias1 = U; + type Alias2>> = U; + + type AB = { a: string; b: string }; + type B = { b: string }; + + type Test1 = Alias1; // ok + type Test2 = Alias2; // ok + + type Test3 = Alias1; // ok + type Test4 = Alias2; // ok + + type WithNumber = { [K in keyof T]: T[K] | number }; + type Alias3>> = U; + + type ABC = { a: string; b: string; c: string }; + + type Test5 = Alias3; // ok + type Test6 = Alias3; // error + ~~~ +!!! error TS2344: Type 'ABC' does not satisfy the constraint 'WithNumber>'. + + type Alias4>>> = U; + + type Test7 = Alias4; // ok + type Test8 = Alias4; // ok + + type Alias5>>> = U; + + type Test9 = Alias5; // ok + type Test10 = Alias5; // ok + + export {}; + \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypeRelationships2.symbols b/tests/baselines/reference/mappedTypeRelationships2.symbols new file mode 100644 index 0000000000000..d0328500a2c01 --- /dev/null +++ b/tests/baselines/reference/mappedTypeRelationships2.symbols @@ -0,0 +1,146 @@ +//// [tests/cases/conformance/types/mapped/mappedTypeRelationships2.ts] //// + +=== mappedTypeRelationships2.ts === +// https://github.com/microsoft/TypeScript/issues/62717 + +type Alias1 = U; +>Alias1 : Symbol(Alias1, Decl(mappedTypeRelationships2.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 2, 12)) +>U : Symbol(U, Decl(mappedTypeRelationships2.ts, 2, 29)) +>K : Symbol(K, Decl(mappedTypeRelationships2.ts, 2, 43)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 2, 12)) +>U : Symbol(U, Decl(mappedTypeRelationships2.ts, 2, 29)) + +type Alias2>> = U; +>Alias2 : Symbol(Alias2, Decl(mappedTypeRelationships2.ts, 2, 70)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 3, 12)) +>U : Symbol(U, Decl(mappedTypeRelationships2.ts, 3, 29)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 3, 12)) +>U : Symbol(U, Decl(mappedTypeRelationships2.ts, 3, 29)) + +type AB = { a: string; b: string }; +>AB : Symbol(AB, Decl(mappedTypeRelationships2.ts, 3, 75)) +>a : Symbol(a, Decl(mappedTypeRelationships2.ts, 5, 11)) +>b : Symbol(b, Decl(mappedTypeRelationships2.ts, 5, 22)) + +type B = { b: string }; +>B : Symbol(B, Decl(mappedTypeRelationships2.ts, 5, 35)) +>b : Symbol(b, Decl(mappedTypeRelationships2.ts, 6, 10)) + +type Test1 = Alias1; // ok +>Test1 : Symbol(Test1, Decl(mappedTypeRelationships2.ts, 6, 23)) +>Alias1 : Symbol(Alias1, Decl(mappedTypeRelationships2.ts, 0, 0)) +>AB : Symbol(AB, Decl(mappedTypeRelationships2.ts, 3, 75)) +>B : Symbol(B, Decl(mappedTypeRelationships2.ts, 5, 35)) + +type Test2 = Alias2; // ok +>Test2 : Symbol(Test2, Decl(mappedTypeRelationships2.ts, 8, 27)) +>Alias2 : Symbol(Alias2, Decl(mappedTypeRelationships2.ts, 2, 70)) +>AB : Symbol(AB, Decl(mappedTypeRelationships2.ts, 3, 75)) +>B : Symbol(B, Decl(mappedTypeRelationships2.ts, 5, 35)) + +type Test3 = Alias1; // ok +>Test3 : Symbol(Test3, Decl(mappedTypeRelationships2.ts, 9, 27)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 11, 11)) +>AB : Symbol(AB, Decl(mappedTypeRelationships2.ts, 3, 75)) +>Alias1 : Symbol(Alias1, Decl(mappedTypeRelationships2.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 11, 11)) +>B : Symbol(B, Decl(mappedTypeRelationships2.ts, 5, 35)) + +type Test4 = Alias2; // ok +>Test4 : Symbol(Test4, Decl(mappedTypeRelationships2.ts, 11, 40)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 12, 11)) +>AB : Symbol(AB, Decl(mappedTypeRelationships2.ts, 3, 75)) +>Alias2 : Symbol(Alias2, Decl(mappedTypeRelationships2.ts, 2, 70)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 12, 11)) +>B : Symbol(B, Decl(mappedTypeRelationships2.ts, 5, 35)) + +type WithNumber = { [K in keyof T]: T[K] | number }; +>WithNumber : Symbol(WithNumber, Decl(mappedTypeRelationships2.ts, 12, 40)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 14, 16)) +>K : Symbol(K, Decl(mappedTypeRelationships2.ts, 14, 24)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 14, 16)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 14, 16)) +>K : Symbol(K, Decl(mappedTypeRelationships2.ts, 14, 24)) + +type Alias3>> = U; +>Alias3 : Symbol(Alias3, Decl(mappedTypeRelationships2.ts, 14, 55)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 15, 12)) +>U : Symbol(U, Decl(mappedTypeRelationships2.ts, 15, 29)) +>WithNumber : Symbol(WithNumber, Decl(mappedTypeRelationships2.ts, 12, 40)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 15, 12)) +>U : Symbol(U, Decl(mappedTypeRelationships2.ts, 15, 29)) + +type ABC = { a: string; b: string; c: string }; +>ABC : Symbol(ABC, Decl(mappedTypeRelationships2.ts, 15, 78)) +>a : Symbol(a, Decl(mappedTypeRelationships2.ts, 17, 12)) +>b : Symbol(b, Decl(mappedTypeRelationships2.ts, 17, 23)) +>c : Symbol(c, Decl(mappedTypeRelationships2.ts, 17, 34)) + +type Test5 = Alias3; // ok +>Test5 : Symbol(Test5, Decl(mappedTypeRelationships2.ts, 17, 47)) +>Alias3 : Symbol(Alias3, Decl(mappedTypeRelationships2.ts, 14, 55)) +>AB : Symbol(AB, Decl(mappedTypeRelationships2.ts, 3, 75)) +>ABC : Symbol(ABC, Decl(mappedTypeRelationships2.ts, 15, 78)) + +type Test6 = Alias3; // error +>Test6 : Symbol(Test6, Decl(mappedTypeRelationships2.ts, 19, 29)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 20, 11)) +>AB : Symbol(AB, Decl(mappedTypeRelationships2.ts, 3, 75)) +>Alias3 : Symbol(Alias3, Decl(mappedTypeRelationships2.ts, 14, 55)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 20, 11)) +>ABC : Symbol(ABC, Decl(mappedTypeRelationships2.ts, 15, 78)) + +type Alias4>>> = U; +>Alias4 : Symbol(Alias4, Decl(mappedTypeRelationships2.ts, 20, 42)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 22, 12)) +>U : Symbol(U, Decl(mappedTypeRelationships2.ts, 22, 29)) +>WithNumber : Symbol(WithNumber, Decl(mappedTypeRelationships2.ts, 12, 40)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 22, 12)) +>U : Symbol(U, Decl(mappedTypeRelationships2.ts, 22, 29)) + +type Test7 = Alias4; // ok +>Test7 : Symbol(Test7, Decl(mappedTypeRelationships2.ts, 22, 87)) +>Alias4 : Symbol(Alias4, Decl(mappedTypeRelationships2.ts, 20, 42)) +>AB : Symbol(AB, Decl(mappedTypeRelationships2.ts, 3, 75)) +>ABC : Symbol(ABC, Decl(mappedTypeRelationships2.ts, 15, 78)) + +type Test8 = Alias4; // ok +>Test8 : Symbol(Test8, Decl(mappedTypeRelationships2.ts, 24, 29)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 25, 11)) +>AB : Symbol(AB, Decl(mappedTypeRelationships2.ts, 3, 75)) +>Alias4 : Symbol(Alias4, Decl(mappedTypeRelationships2.ts, 20, 42)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 25, 11)) +>ABC : Symbol(ABC, Decl(mappedTypeRelationships2.ts, 15, 78)) + +type Alias5>>> = U; +>Alias5 : Symbol(Alias5, Decl(mappedTypeRelationships2.ts, 25, 42)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 27, 12)) +>U : Symbol(U, Decl(mappedTypeRelationships2.ts, 27, 29)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>WithNumber : Symbol(WithNumber, Decl(mappedTypeRelationships2.ts, 12, 40)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 27, 12)) +>U : Symbol(U, Decl(mappedTypeRelationships2.ts, 27, 29)) + +type Test9 = Alias5; // ok +>Test9 : Symbol(Test9, Decl(mappedTypeRelationships2.ts, 27, 87)) +>Alias5 : Symbol(Alias5, Decl(mappedTypeRelationships2.ts, 25, 42)) +>AB : Symbol(AB, Decl(mappedTypeRelationships2.ts, 3, 75)) +>ABC : Symbol(ABC, Decl(mappedTypeRelationships2.ts, 15, 78)) + +type Test10 = Alias5; // ok +>Test10 : Symbol(Test10, Decl(mappedTypeRelationships2.ts, 29, 29)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 30, 12)) +>AB : Symbol(AB, Decl(mappedTypeRelationships2.ts, 3, 75)) +>Alias5 : Symbol(Alias5, Decl(mappedTypeRelationships2.ts, 25, 42)) +>T : Symbol(T, Decl(mappedTypeRelationships2.ts, 30, 12)) +>ABC : Symbol(ABC, Decl(mappedTypeRelationships2.ts, 15, 78)) + +export {}; + diff --git a/tests/baselines/reference/mappedTypeRelationships2.types b/tests/baselines/reference/mappedTypeRelationships2.types new file mode 100644 index 0000000000000..667642744f899 --- /dev/null +++ b/tests/baselines/reference/mappedTypeRelationships2.types @@ -0,0 +1,95 @@ +//// [tests/cases/conformance/types/mapped/mappedTypeRelationships2.ts] //// + +=== mappedTypeRelationships2.ts === +// https://github.com/microsoft/TypeScript/issues/62717 + +type Alias1 = U; +>Alias1 : U +> : ^ + +type Alias2>> = U; +>Alias2 : U +> : ^ + +type AB = { a: string; b: string }; +>AB : AB +> : ^^ +>a : string +> : ^^^^^^ +>b : string +> : ^^^^^^ + +type B = { b: string }; +>B : B +> : ^ +>b : string +> : ^^^^^^ + +type Test1 = Alias1; // ok +>Test1 : B +> : ^ + +type Test2 = Alias2; // ok +>Test2 : B +> : ^ + +type Test3 = Alias1; // ok +>Test3 : B +> : ^ + +type Test4 = Alias2; // ok +>Test4 : B +> : ^ + +type WithNumber = { [K in keyof T]: T[K] | number }; +>WithNumber : WithNumber +> : ^^^^^^^^^^^^^ + +type Alias3>> = U; +>Alias3 : U +> : ^ + +type ABC = { a: string; b: string; c: string }; +>ABC : ABC +> : ^^^ +>a : string +> : ^^^^^^ +>b : string +> : ^^^^^^ +>c : string +> : ^^^^^^ + +type Test5 = Alias3; // ok +>Test5 : ABC +> : ^^^ + +type Test6 = Alias3; // error +>Test6 : ABC +> : ^^^ + +type Alias4>>> = U; +>Alias4 : U +> : ^ + +type Test7 = Alias4; // ok +>Test7 : ABC +> : ^^^ + +type Test8 = Alias4; // ok +>Test8 : ABC +> : ^^^ + +type Alias5>>> = U; +>Alias5 : U +> : ^ + +type Test9 = Alias5; // ok +>Test9 : ABC +> : ^^^ + +type Test10 = Alias5; // ok +>Test10 : ABC +> : ^^^ + +export {}; + diff --git a/tests/cases/conformance/types/mapped/mappedTypeRelationships2.ts b/tests/cases/conformance/types/mapped/mappedTypeRelationships2.ts new file mode 100644 index 0000000000000..415c7870918fa --- /dev/null +++ b/tests/cases/conformance/types/mapped/mappedTypeRelationships2.ts @@ -0,0 +1,36 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/62717 + +type Alias1 = U; +type Alias2>> = U; + +type AB = { a: string; b: string }; +type B = { b: string }; + +type Test1 = Alias1; // ok +type Test2 = Alias2; // ok + +type Test3 = Alias1; // ok +type Test4 = Alias2; // ok + +type WithNumber = { [K in keyof T]: T[K] | number }; +type Alias3>> = U; + +type ABC = { a: string; b: string; c: string }; + +type Test5 = Alias3; // ok +type Test6 = Alias3; // error + +type Alias4>>> = U; + +type Test7 = Alias4; // ok +type Test8 = Alias4; // ok + +type Alias5>>> = U; + +type Test9 = Alias5; // ok +type Test10 = Alias5; // ok + +export {};