Fixed const reverse mapped types themselves to be treated as const (#55794)

This commit is contained in:
Mateusz Burzyński 2023-11-27 21:57:57 +01:00 committed by GitHub
parent 2d4cacdf39
commit c474123b47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 315 additions and 2 deletions

View File

@ -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
));
}

View File

@ -402,8 +402,8 @@ const thingMapped = <const O extends Record<string, any>>(o: NotEmptyMapped<O>)
>o : NotEmptyMapped<O>
const tMapped = thingMapped({ foo: '' }); // { foo: "" }
>tMapped : { foo: ""; }
>thingMapped({ foo: '' }) : { foo: ""; }
>tMapped : { readonly foo: ""; }
>thingMapped({ foo: '' }) : { readonly foo: ""; }
>thingMapped : <const O extends Record<string, any>>(o: NotEmptyMapped<O>) => NotEmptyMapped<O>
>{ foo: '' } : { foo: ""; }
>foo : ""

View File

@ -0,0 +1,135 @@
//// [tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiersReverseMappedTypes.ts] ////
=== typeParameterConstModifiersReverseMappedTypes.ts ===
declare function test1<const T>(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<const T>(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<const T>(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<const T extends readonly unknown[]>(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<const T extends readonly unknown[]>(
>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))

View File

@ -0,0 +1,123 @@
//// [tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiersReverseMappedTypes.ts] ////
=== typeParameterConstModifiersReverseMappedTypes.ts ===
declare function test1<const T>(obj: {
>test1 : <const T>(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 : <const T>(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<const T>(obj: {
>test2 : <const T>(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 : <const T>(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<const T>(obj: {
>test3 : <const T>(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 : <const T>(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<const T extends readonly unknown[]>(arr: {
>test4 : <const T extends readonly unknown[]>(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 : <const T extends readonly unknown[]>(arr: { [K in keyof T]: T[K]; }) => T
>["1", 2] : ["1", 2]
>"1" : "1"
>2 : 2
declare function test5<const T extends readonly unknown[]>(
>test5 : <const T extends readonly unknown[]>(...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 : <const T extends readonly unknown[]>(...args: { [K in keyof T]: T[K]; }) => T
>{ a: "foo" } : { a: "foo"; }
>a : "foo"
>"foo" : "foo"

View File

@ -0,0 +1,49 @@
// @strict: true
// @noEmit: true
declare function test1<const T>(obj: {
[K in keyof T]: T[K];
}): [T, typeof obj];
const result1 = test1({
prop: "foo",
nested: {
nestedProp: "bar",
},
});
declare function test2<const T>(obj: {
readonly [K in keyof T]: T[K];
}): [T, typeof obj];
const result2 = test2({
prop: "foo",
nested: {
nestedProp: "bar",
},
});
declare function test3<const T>(obj: {
-readonly [K in keyof T]: T[K];
}): [T, typeof obj];
const result3 = test3({
prop: "foo",
nested: {
nestedProp: "bar",
},
});
declare function test4<const T extends readonly unknown[]>(arr: {
[K in keyof T]: T[K];
}): T;
const result4 = test4(["1", 2]);
declare function test5<const T extends readonly unknown[]>(
...args: {
[K in keyof T]: T[K];
}
): T;
const result5 = test5({ a: "foo" });