diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 985b0f4968670..9c084ae06b2c6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14055,6 +14055,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined; } + function isConstMappedType(type: MappedType, depth: number): boolean { + const typeVariable = getHomomorphicTypeVariable(type); + return !!typeVariable && isConstTypeVariable(typeVariable, depth); + } + function isConstTypeVariable(type: Type | undefined, depth = 0): boolean { return depth < 5 && !!(type && ( type.flags & TypeFlags.TypeParameter && some((type as TypeParameter).symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Const)) || @@ -14062,6 +14067,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType, depth + 1) || type.flags & TypeFlags.Conditional && isConstTypeVariable(getConstraintOfConditionalType(type as ConditionalType), depth + 1) || type.flags & TypeFlags.Substitution && isConstTypeVariable((type as SubstitutionType).baseType, depth) || + getObjectFlags(type) & ObjectFlags.Mapped && isConstMappedType(type as MappedType, depth) || isGenericTupleType(type) && findIndex(getElementTypes(type), (t, i) => !!(type.target.elementFlags[i] & ElementFlags.Variadic) && isConstTypeVariable(t, depth)) >= 0 )); } diff --git a/tests/baselines/reference/typeParameterConstModifiers.types b/tests/baselines/reference/typeParameterConstModifiers.types index 5f7e230e14a25..bf3732eb5a64a 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.types +++ b/tests/baselines/reference/typeParameterConstModifiers.types @@ -402,8 +402,8 @@ const thingMapped = >(o: NotEmptyMapped) >o : NotEmptyMapped const tMapped = thingMapped({ foo: '' }); // { foo: "" } ->tMapped : { foo: ""; } ->thingMapped({ foo: '' }) : { foo: ""; } +>tMapped : { readonly foo: ""; } +>thingMapped({ foo: '' }) : { readonly foo: ""; } >thingMapped : >(o: NotEmptyMapped) => NotEmptyMapped >{ foo: '' } : { foo: ""; } >foo : "" diff --git a/tests/baselines/reference/typeParameterConstModifiersReverseMappedTypes.symbols b/tests/baselines/reference/typeParameterConstModifiersReverseMappedTypes.symbols new file mode 100644 index 0000000000000..5afa119b16a06 --- /dev/null +++ b/tests/baselines/reference/typeParameterConstModifiersReverseMappedTypes.symbols @@ -0,0 +1,135 @@ +//// [tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiersReverseMappedTypes.ts] //// + +=== typeParameterConstModifiersReverseMappedTypes.ts === +declare function test1(obj: { +>test1 : Symbol(test1, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 0)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 23)) +>obj : Symbol(obj, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 32)) + + [K in keyof T]: T[K]; +>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 1, 3)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 23)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 23)) +>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 1, 3)) + +}): [T, typeof obj]; +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 23)) +>obj : Symbol(obj, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 32)) + +const result1 = test1({ +>result1 : Symbol(result1, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 4, 5)) +>test1 : Symbol(test1, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 0, 0)) + + prop: "foo", +>prop : Symbol(prop, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 4, 23)) + + nested: { +>nested : Symbol(nested, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 5, 14)) + + nestedProp: "bar", +>nestedProp : Symbol(nestedProp, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 6, 11)) + + }, +}); + +declare function test2(obj: { +>test2 : Symbol(test2, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 9, 3)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 11, 23)) +>obj : Symbol(obj, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 11, 32)) + + readonly [K in keyof T]: T[K]; +>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 12, 12)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 11, 23)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 11, 23)) +>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 12, 12)) + +}): [T, typeof obj]; +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 11, 23)) +>obj : Symbol(obj, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 11, 32)) + +const result2 = test2({ +>result2 : Symbol(result2, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 15, 5)) +>test2 : Symbol(test2, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 9, 3)) + + prop: "foo", +>prop : Symbol(prop, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 15, 23)) + + nested: { +>nested : Symbol(nested, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 16, 14)) + + nestedProp: "bar", +>nestedProp : Symbol(nestedProp, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 17, 11)) + + }, +}); + +declare function test3(obj: { +>test3 : Symbol(test3, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 20, 3)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 22, 23)) +>obj : Symbol(obj, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 22, 32)) + + -readonly [K in keyof T]: T[K]; +>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 23, 13)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 22, 23)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 22, 23)) +>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 23, 13)) + +}): [T, typeof obj]; +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 22, 23)) +>obj : Symbol(obj, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 22, 32)) + +const result3 = test3({ +>result3 : Symbol(result3, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 26, 5)) +>test3 : Symbol(test3, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 20, 3)) + + prop: "foo", +>prop : Symbol(prop, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 26, 23)) + + nested: { +>nested : Symbol(nested, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 27, 14)) + + nestedProp: "bar", +>nestedProp : Symbol(nestedProp, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 28, 11)) + + }, +}); + +declare function test4(arr: { +>test4 : Symbol(test4, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 31, 3)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 33, 23)) +>arr : Symbol(arr, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 33, 59)) + + [K in keyof T]: T[K]; +>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 34, 3)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 33, 23)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 33, 23)) +>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 34, 3)) + +}): T; +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 33, 23)) + +const result4 = test4(["1", 2]); +>result4 : Symbol(result4, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 37, 5)) +>test4 : Symbol(test4, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 31, 3)) + +declare function test5( +>test5 : Symbol(test5, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 37, 32)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 39, 23)) + + ...args: { +>args : Symbol(args, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 39, 59)) + + [K in keyof T]: T[K]; +>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 41, 5)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 39, 23)) +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 39, 23)) +>K : Symbol(K, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 41, 5)) + } +): T; +>T : Symbol(T, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 39, 23)) + +const result5 = test5({ a: "foo" }); +>result5 : Symbol(result5, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 45, 5)) +>test5 : Symbol(test5, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 37, 32)) +>a : Symbol(a, Decl(typeParameterConstModifiersReverseMappedTypes.ts, 45, 23)) + diff --git a/tests/baselines/reference/typeParameterConstModifiersReverseMappedTypes.types b/tests/baselines/reference/typeParameterConstModifiersReverseMappedTypes.types new file mode 100644 index 0000000000000..fc0a572141951 --- /dev/null +++ b/tests/baselines/reference/typeParameterConstModifiersReverseMappedTypes.types @@ -0,0 +1,123 @@ +//// [tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiersReverseMappedTypes.ts] //// + +=== typeParameterConstModifiersReverseMappedTypes.ts === +declare function test1(obj: { +>test1 : (obj: { [K in keyof T]: T[K]; }) => [T, typeof obj] +>obj : { [K in keyof T]: T[K]; } + + [K in keyof T]: T[K]; +}): [T, typeof obj]; +>obj : { [K in keyof T]: T[K]; } + +const result1 = test1({ +>result1 : [{ readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }, { readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }] +>test1({ prop: "foo", nested: { nestedProp: "bar", },}) : [{ readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }, { readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }] +>test1 : (obj: { [K in keyof T]: T[K]; }) => [T, { [K in keyof T]: T[K]; }] +>{ prop: "foo", nested: { nestedProp: "bar", },} : { prop: "foo"; nested: { nestedProp: "bar"; }; } + + prop: "foo", +>prop : "foo" +>"foo" : "foo" + + nested: { +>nested : { nestedProp: "bar"; } +>{ nestedProp: "bar", } : { nestedProp: "bar"; } + + nestedProp: "bar", +>nestedProp : "bar" +>"bar" : "bar" + + }, +}); + +declare function test2(obj: { +>test2 : (obj: { readonly [K in keyof T]: T[K]; }) => [T, typeof obj] +>obj : { readonly [K in keyof T]: T[K]; } + + readonly [K in keyof T]: T[K]; +}): [T, typeof obj]; +>obj : { readonly [K in keyof T]: T[K]; } + +const result2 = test2({ +>result2 : [{ prop: "foo"; nested: { readonly nestedProp: "bar"; }; }, { readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }] +>test2({ prop: "foo", nested: { nestedProp: "bar", },}) : [{ prop: "foo"; nested: { readonly nestedProp: "bar"; }; }, { readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }] +>test2 : (obj: { readonly [K in keyof T]: T[K]; }) => [T, { readonly [K in keyof T]: T[K]; }] +>{ prop: "foo", nested: { nestedProp: "bar", },} : { prop: "foo"; nested: { nestedProp: "bar"; }; } + + prop: "foo", +>prop : "foo" +>"foo" : "foo" + + nested: { +>nested : { nestedProp: "bar"; } +>{ nestedProp: "bar", } : { nestedProp: "bar"; } + + nestedProp: "bar", +>nestedProp : "bar" +>"bar" : "bar" + + }, +}); + +declare function test3(obj: { +>test3 : (obj: { -readonly [K in keyof T]: T[K]; }) => [T, typeof obj] +>obj : { -readonly [K in keyof T]: T[K]; } + + -readonly [K in keyof T]: T[K]; +}): [T, typeof obj]; +>obj : { -readonly [K in keyof T]: T[K]; } + +const result3 = test3({ +>result3 : [{ readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }, { prop: "foo"; nested: { readonly nestedProp: "bar"; }; }] +>test3({ prop: "foo", nested: { nestedProp: "bar", },}) : [{ readonly prop: "foo"; readonly nested: { readonly nestedProp: "bar"; }; }, { prop: "foo"; nested: { readonly nestedProp: "bar"; }; }] +>test3 : (obj: { -readonly [K in keyof T]: T[K]; }) => [T, { -readonly [K in keyof T]: T[K]; }] +>{ prop: "foo", nested: { nestedProp: "bar", },} : { prop: "foo"; nested: { nestedProp: "bar"; }; } + + prop: "foo", +>prop : "foo" +>"foo" : "foo" + + nested: { +>nested : { nestedProp: "bar"; } +>{ nestedProp: "bar", } : { nestedProp: "bar"; } + + nestedProp: "bar", +>nestedProp : "bar" +>"bar" : "bar" + + }, +}); + +declare function test4(arr: { +>test4 : (arr: { [K in keyof T]: T[K]; }) => T +>arr : { [K in keyof T]: T[K]; } + + [K in keyof T]: T[K]; +}): T; + +const result4 = test4(["1", 2]); +>result4 : readonly ["1", 2] +>test4(["1", 2]) : readonly ["1", 2] +>test4 : (arr: { [K in keyof T]: T[K]; }) => T +>["1", 2] : ["1", 2] +>"1" : "1" +>2 : 2 + +declare function test5( +>test5 : (...args: { [K in keyof T]: T[K]; }) => T + + ...args: { +>args : { [K in keyof T]: T[K]; } + + [K in keyof T]: T[K]; + } +): T; + +const result5 = test5({ a: "foo" }); +>result5 : readonly [{ readonly a: "foo"; }] +>test5({ a: "foo" }) : readonly [{ readonly a: "foo"; }] +>test5 : (...args: { [K in keyof T]: T[K]; }) => T +>{ a: "foo" } : { a: "foo"; } +>a : "foo" +>"foo" : "foo" + diff --git a/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiersReverseMappedTypes.ts b/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiersReverseMappedTypes.ts new file mode 100644 index 0000000000000..a8ffbea7d6459 --- /dev/null +++ b/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiersReverseMappedTypes.ts @@ -0,0 +1,49 @@ +// @strict: true +// @noEmit: true + +declare function test1(obj: { + [K in keyof T]: T[K]; +}): [T, typeof obj]; + +const result1 = test1({ + prop: "foo", + nested: { + nestedProp: "bar", + }, +}); + +declare function test2(obj: { + readonly [K in keyof T]: T[K]; +}): [T, typeof obj]; + +const result2 = test2({ + prop: "foo", + nested: { + nestedProp: "bar", + }, +}); + +declare function test3(obj: { + -readonly [K in keyof T]: T[K]; +}): [T, typeof obj]; + +const result3 = test3({ + prop: "foo", + nested: { + nestedProp: "bar", + }, +}); + +declare function test4(arr: { + [K in keyof T]: T[K]; +}): T; + +const result4 = test4(["1", 2]); + +declare function test5( + ...args: { + [K in keyof T]: T[K]; + } +): T; + +const result5 = test5({ a: "foo" });