diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 69933033d3929..2fbdccba85bbf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23568,22 +23568,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { !hasBaseType(checkClass, getDeclaringClass(p)) : false) ? undefined : checkClass; } - // Return true if the given type is deeply nested. We consider this to be the case when structural type comparisons - // for maxDepth or more occurrences or instantiations of the same type have been recorded on the given stack. The - // "sameness" of instantiations is determined by the getRecursionIdentity function. An intersection is considered - // deeply nested if any constituent of the intersection is deeply nested. It is possible, though highly unlikely, for - // the deeply nested check to be true in a situation where a chain of instantiations is not infinitely expanding. - // Effectively, we will generate a false positive when two types are structurally equal to at least maxDepth levels, - // but unequal at some level beyond that. - // In addition, this will also detect when an indexed access has been chained off of maxDepth more times (which is - // essentially the dual of the structural comparison), and likewise mark the type as deeply nested, potentially adding - // false positives for finite but deeply expanding indexed accesses (eg, for `Q[P1][P2][P3][P4][P5]`). - // It also detects when a recursive type reference has expanded maxDepth or more times, e.g. if the true branch of - // `type A = null extends T ? [A>] : [T]` - // has expanded into `[A>>>>>]`. In such cases we need - // to terminate the expansion, and we do so here. + // Return true if the given type is deeply nested. We consider this to be the case when the given stack contains + // maxDepth or more occurrences of types with the same recursion identity as the given type. The recursion identity + // provides a shared identity for type instantiations that repeat in some (possibly infinite) pattern. For example, + // in `type Deep = { next: Deep> }`, repeatedly referencing the `next` property leads to an infinite + // sequence of ever deeper instantiations with the same recursion identity (in this case the symbol associated with + // the object type literal). + // A homomorphic mapped type is considered deeply nested if its target type is deeply nested, and an intersection is + // considered deeply nested if any constituent of the intersection is deeply nested. + // It is possible, though highly unlikely, for the deeply nested check to be true in a situation where a chain of + // instantiations is not infinitely expanding. Effectively, we will generate a false positive when two types are + // structurally equal to at least maxDepth levels, but unequal at some level beyond that. function isDeeplyNestedType(type: Type, stack: Type[], depth: number, maxDepth = 3): boolean { if (depth >= maxDepth) { + if ((getObjectFlags(type) & ObjectFlags.InstantiatedMapped) === ObjectFlags.InstantiatedMapped) { + type = getMappedTargetWithSymbol(type); + } if (type.flags & TypeFlags.Intersection) { return some((type as IntersectionType).types, t => isDeeplyNestedType(t, stack, depth, maxDepth)); } @@ -23592,7 +23592,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let lastTypeId = 0; for (let i = 0; i < depth; i++) { const t = stack[i]; - if (t.flags & TypeFlags.Intersection ? some((t as IntersectionType).types, u => getRecursionIdentity(u) === identity) : getRecursionIdentity(t) === identity) { + if (hasMatchingRecursionIdentity(t, identity)) { // We only count occurrences with a higher type id than the previous occurrence, since higher // type ids are an indicator of newer instantiations caused by recursion. if (t.id >= lastTypeId) { @@ -23608,6 +23608,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } + // Unwrap nested homomorphic mapped types and return the deepest target type that has a symbol. This better + // preserves unique type identities for mapped types applied to explicitly written object literals. For example + // in `Mapped<{ x: Mapped<{ x: Mapped<{ x: string }>}>}>`, each of the mapped type applications will have a + // unique recursion identity (that of their target object type literal) and thus avoid appearing deeply nested. + function getMappedTargetWithSymbol(type: Type) { + let target; + while ( + (getObjectFlags(type) & ObjectFlags.InstantiatedMapped) === ObjectFlags.InstantiatedMapped && + (target = getModifiersTypeFromMappedType(type as MappedType)) && + (target.symbol || target.flags & TypeFlags.Intersection && some((target as IntersectionType).types, t => !!t.symbol)) + ) { + type = target; + } + return type; + } + + function hasMatchingRecursionIdentity(type: Type, identity: object): boolean { + if ((getObjectFlags(type) & ObjectFlags.InstantiatedMapped) === ObjectFlags.InstantiatedMapped) { + type = getMappedTargetWithSymbol(type); + } + if (type.flags & TypeFlags.Intersection) { + return some((type as IntersectionType).types, t => hasMatchingRecursionIdentity(t, identity)); + } + return getRecursionIdentity(type) === identity; + } + // The recursion identity of a type is an object identity that is shared among multiple instantiations of the type. // We track recursion identities in order to identify deeply nested and possibly infinite type instantiations with // the same origin. For example, when type parameters are in scope in an object type such as { x: T }, all @@ -23623,28 +23649,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // unique AST node. return (type as TypeReference).node!; } - if (type.symbol) { - // We track object types that have a symbol by that symbol (representing the origin of the type). - if (getObjectFlags(type) & ObjectFlags.Mapped) { - // When a homomorphic mapped type is applied to a type with a symbol, we use the symbol of that - // type as the recursion identity. This is a better strategy than using the symbol of the mapped - // type, which doesn't work well for recursive mapped types. - type = getMappedTargetWithSymbol(type); - } - if (!(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol.flags & SymbolFlags.Class)) { - // We exclude the static side of a class since it shares its symbol with the instance side. - return type.symbol; - } + if (type.symbol && !(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol.flags & SymbolFlags.Class)) { + // We track object types that have a symbol by that symbol (representing the origin of the type), but + // exclude the static side of a class since it shares its symbol with the instance side. + return type.symbol; } if (isTupleType(type)) { return type.target; } } if (type.flags & TypeFlags.TypeParameter) { + // We use the symbol of the type parameter such that all "fresh" instantiations of that type parameter + // have the same recursion identity. return type.symbol; } if (type.flags & TypeFlags.IndexedAccess) { - // Identity is the leftmost object type in a chain of indexed accesses, eg, in A[P][Q] it is A + // Identity is the leftmost object type in a chain of indexed accesses, eg, in A[P1][P2][P3] it is A. do { type = (type as IndexedAccessType).objectType; } @@ -23658,14 +23678,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function getMappedTargetWithSymbol(type: Type) { - let target = type; - while ((getObjectFlags(target) & ObjectFlags.InstantiatedMapped) === ObjectFlags.InstantiatedMapped && isMappedTypeWithKeyofConstraintDeclaration(target as MappedType)) { - target = getModifiersTypeFromMappedType(target as MappedType); - } - return target.symbol ? target : type; - } - function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean { return compareProperties(sourceProp, targetProp, compareTypesIdentical) !== Ternary.False; } diff --git a/tests/baselines/reference/deeplyNestedMappedTypes.errors.txt b/tests/baselines/reference/deeplyNestedMappedTypes.errors.txt index 7882bbfc99f06..d9cd2e20c31d8 100644 --- a/tests/baselines/reference/deeplyNestedMappedTypes.errors.txt +++ b/tests/baselines/reference/deeplyNestedMappedTypes.errors.txt @@ -4,9 +4,19 @@ deeplyNestedMappedTypes.ts(9,7): error TS2322: Type 'Id<{ x: { y: { z: { a: { b: deeplyNestedMappedTypes.ts(17,7): error TS2322: Type 'Id2<{ x: { y: { z: { a: { b: { c: number; }; }; }; }; }; }>' is not assignable to type 'Id2<{ x: { y: { z: { a: { b: { c: string; }; }; }; }; }; }>'. The types of 'x.y.z.a.b.c' are incompatible between these types. Type 'number' is not assignable to type 'string'. +deeplyNestedMappedTypes.ts(69,5): error TS2322: Type '{ level1: { level2: { foo: string; }; }; }[]' is not assignable to type '{ level1: { level2: { foo: string; bar: string; }; }; }[]'. + Type '{ level1: { level2: { foo: string; }; }; }' is not assignable to type '{ level1: { level2: { foo: string; bar: string; }; }; }'. + The types of 'level1.level2' are incompatible between these types. + Property 'bar' is missing in type '{ foo: string; }' but required in type '{ foo: string; bar: string; }'. +deeplyNestedMappedTypes.ts(73,5): error TS2322: Type '{ level1: { level2: { foo: string; }; }; }[]' is not assignable to type 'T'. + 'T' could be instantiated with an arbitrary type which could be unrelated to '{ level1: { level2: { foo: string; }; }; }[]'. +deeplyNestedMappedTypes.ts(77,5): error TS2322: Type '{ level1: { level2: { foo: string; }; }; }[]' is not assignable to type '{ level1: { level2: { foo: string; bar: string; }; }; }[]'. + Type '{ level1: { level2: { foo: string; }; }; }' is not assignable to type '{ level1: { level2: { foo: string; bar: string; }; }; }'. + The types of 'level1.level2' are incompatible between these types. + Property 'bar' is missing in type '{ foo: string; }' but required in type '{ foo: string; bar: string; }'. -==== deeplyNestedMappedTypes.ts (2 errors) ==== +==== deeplyNestedMappedTypes.ts (5 errors) ==== // Simplified repro from #55535 type Id = { [K in keyof T]: Id }; @@ -60,4 +70,109 @@ deeplyNestedMappedTypes.ts(17,7): error TS2322: Type 'Id2<{ x: { y: { z: { a: { declare const bar1: Bar1; const bar2: Bar2 = bar1; // Error expected + + // Repro from #56138 + + export type Input = Static + export const Input = Type.Object({ + level1: Type.Object({ + level2: Type.Object({ + foo: Type.String(), + }) + }) + }) + + export type Output = Static + export const Output = Type.Object({ + level1: Type.Object({ + level2: Type.Object({ + foo: Type.String(), + bar: Type.String(), + }) + }) + }) + + function problematicFunction1(ors: Input[]): Output[] { + return ors; // Error + ~~~~~~ +!!! error TS2322: Type '{ level1: { level2: { foo: string; }; }; }[]' is not assignable to type '{ level1: { level2: { foo: string; bar: string; }; }; }[]'. +!!! error TS2322: Type '{ level1: { level2: { foo: string; }; }; }' is not assignable to type '{ level1: { level2: { foo: string; bar: string; }; }; }'. +!!! error TS2322: The types of 'level1.level2' are incompatible between these types. +!!! error TS2322: Property 'bar' is missing in type '{ foo: string; }' but required in type '{ foo: string; bar: string; }'. +!!! related TS2728 deeplyNestedMappedTypes.ts:63:13: 'bar' is declared here. + } + + function problematicFunction2(ors: Input[]): T { + return ors; // Error + ~~~~~~ +!!! error TS2322: Type '{ level1: { level2: { foo: string; }; }; }[]' is not assignable to type 'T'. +!!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to '{ level1: { level2: { foo: string; }; }; }[]'. + } + + function problematicFunction3(ors: (typeof Input.static)[]): Output[] { + return ors; // Error + ~~~~~~ +!!! error TS2322: Type '{ level1: { level2: { foo: string; }; }; }[]' is not assignable to type '{ level1: { level2: { foo: string; bar: string; }; }; }[]'. +!!! error TS2322: Type '{ level1: { level2: { foo: string; }; }; }' is not assignable to type '{ level1: { level2: { foo: string; bar: string; }; }; }'. +!!! error TS2322: The types of 'level1.level2' are incompatible between these types. +!!! error TS2322: Property 'bar' is missing in type '{ foo: string; }' but required in type '{ foo: string; bar: string; }'. +!!! related TS2728 deeplyNestedMappedTypes.ts:63:13: 'bar' is declared here. + } + + export type Evaluate = T extends infer O ? { [K in keyof O]: O[K] } : never + + export declare const Readonly: unique symbol; + export declare const Optional: unique symbol; + export declare const Hint: unique symbol; + export declare const Kind: unique symbol; + + export interface TKind { + [Kind]: string + } + export interface TSchema extends TKind { + [Readonly]?: string + [Optional]?: string + [Hint]?: string + params: unknown[] + static: unknown + } + + export type TReadonlyOptional = TOptional & TReadonly + export type TReadonly = T & { [Readonly]: 'Readonly' } + export type TOptional = T & { [Optional]: 'Optional' } + + export interface TString extends TSchema { + [Kind]: 'String'; + static: string; + type: 'string'; + } + + export type ReadonlyOptionalPropertyKeys = { [K in keyof T]: T[K] extends TReadonly ? (T[K] extends TOptional ? K : never) : never }[keyof T] + export type ReadonlyPropertyKeys = { [K in keyof T]: T[K] extends TReadonly ? (T[K] extends TOptional ? never : K) : never }[keyof T] + export type OptionalPropertyKeys = { [K in keyof T]: T[K] extends TOptional ? (T[K] extends TReadonly ? never : K) : never }[keyof T] + export type RequiredPropertyKeys = keyof Omit | ReadonlyPropertyKeys | OptionalPropertyKeys> + export type PropertiesReducer> = Evaluate<( + Readonly>>> & + Readonly>> & + Partial>> & + Required>> + )> + export type PropertiesReduce = PropertiesReducer + }> + export type TPropertyKey = string | number + export type TProperties = Record + export interface TObject extends TSchema { + [Kind]: 'Object' + static: PropertiesReduce + type: 'object' + properties: T + } + + export type Static = (T & { params: P; })['static'] + + declare namespace Type { + function Object(object: T): TObject + function String(): TString + } \ No newline at end of file diff --git a/tests/baselines/reference/deeplyNestedMappedTypes.symbols b/tests/baselines/reference/deeplyNestedMappedTypes.symbols index 9a67e438cd172..668ef4bf245a4 100644 --- a/tests/baselines/reference/deeplyNestedMappedTypes.symbols +++ b/tests/baselines/reference/deeplyNestedMappedTypes.symbols @@ -175,3 +175,384 @@ const bar2: Bar2 = bar1; // Error expected >Bar2 : Symbol(Bar2, Decl(deeplyNestedMappedTypes.ts, 40, 48)) >bar1 : Symbol(bar1, Decl(deeplyNestedMappedTypes.ts, 43, 13)) +// Repro from #56138 + +export type Input = Static +>Input : Symbol(Input, Decl(deeplyNestedMappedTypes.ts, 44, 24), Decl(deeplyNestedMappedTypes.ts, 49, 12)) +>Static : Symbol(Static, Decl(deeplyNestedMappedTypes.ts, 127, 1)) +>Input : Symbol(Input, Decl(deeplyNestedMappedTypes.ts, 44, 24), Decl(deeplyNestedMappedTypes.ts, 49, 12)) + +export const Input = Type.Object({ +>Input : Symbol(Input, Decl(deeplyNestedMappedTypes.ts, 44, 24), Decl(deeplyNestedMappedTypes.ts, 49, 12)) +>Type.Object : Symbol(Type.Object, Decl(deeplyNestedMappedTypes.ts, 131, 24)) +>Type : Symbol(Type, Decl(deeplyNestedMappedTypes.ts, 129, 96)) +>Object : Symbol(Type.Object, Decl(deeplyNestedMappedTypes.ts, 131, 24)) + + level1: Type.Object({ +>level1 : Symbol(level1, Decl(deeplyNestedMappedTypes.ts, 49, 34)) +>Type.Object : Symbol(Type.Object, Decl(deeplyNestedMappedTypes.ts, 131, 24)) +>Type : Symbol(Type, Decl(deeplyNestedMappedTypes.ts, 129, 96)) +>Object : Symbol(Type.Object, Decl(deeplyNestedMappedTypes.ts, 131, 24)) + + level2: Type.Object({ +>level2 : Symbol(level2, Decl(deeplyNestedMappedTypes.ts, 50, 25)) +>Type.Object : Symbol(Type.Object, Decl(deeplyNestedMappedTypes.ts, 131, 24)) +>Type : Symbol(Type, Decl(deeplyNestedMappedTypes.ts, 129, 96)) +>Object : Symbol(Type.Object, Decl(deeplyNestedMappedTypes.ts, 131, 24)) + + foo: Type.String(), +>foo : Symbol(foo, Decl(deeplyNestedMappedTypes.ts, 51, 29)) +>Type.String : Symbol(Type.String, Decl(deeplyNestedMappedTypes.ts, 132, 65)) +>Type : Symbol(Type, Decl(deeplyNestedMappedTypes.ts, 129, 96)) +>String : Symbol(Type.String, Decl(deeplyNestedMappedTypes.ts, 132, 65)) + + }) + }) +}) + +export type Output = Static +>Output : Symbol(Output, Decl(deeplyNestedMappedTypes.ts, 55, 2), Decl(deeplyNestedMappedTypes.ts, 58, 12)) +>Static : Symbol(Static, Decl(deeplyNestedMappedTypes.ts, 127, 1)) +>Output : Symbol(Output, Decl(deeplyNestedMappedTypes.ts, 55, 2), Decl(deeplyNestedMappedTypes.ts, 58, 12)) + +export const Output = Type.Object({ +>Output : Symbol(Output, Decl(deeplyNestedMappedTypes.ts, 55, 2), Decl(deeplyNestedMappedTypes.ts, 58, 12)) +>Type.Object : Symbol(Type.Object, Decl(deeplyNestedMappedTypes.ts, 131, 24)) +>Type : Symbol(Type, Decl(deeplyNestedMappedTypes.ts, 129, 96)) +>Object : Symbol(Type.Object, Decl(deeplyNestedMappedTypes.ts, 131, 24)) + + level1: Type.Object({ +>level1 : Symbol(level1, Decl(deeplyNestedMappedTypes.ts, 58, 35)) +>Type.Object : Symbol(Type.Object, Decl(deeplyNestedMappedTypes.ts, 131, 24)) +>Type : Symbol(Type, Decl(deeplyNestedMappedTypes.ts, 129, 96)) +>Object : Symbol(Type.Object, Decl(deeplyNestedMappedTypes.ts, 131, 24)) + + level2: Type.Object({ +>level2 : Symbol(level2, Decl(deeplyNestedMappedTypes.ts, 59, 25)) +>Type.Object : Symbol(Type.Object, Decl(deeplyNestedMappedTypes.ts, 131, 24)) +>Type : Symbol(Type, Decl(deeplyNestedMappedTypes.ts, 129, 96)) +>Object : Symbol(Type.Object, Decl(deeplyNestedMappedTypes.ts, 131, 24)) + + foo: Type.String(), +>foo : Symbol(foo, Decl(deeplyNestedMappedTypes.ts, 60, 29)) +>Type.String : Symbol(Type.String, Decl(deeplyNestedMappedTypes.ts, 132, 65)) +>Type : Symbol(Type, Decl(deeplyNestedMappedTypes.ts, 129, 96)) +>String : Symbol(Type.String, Decl(deeplyNestedMappedTypes.ts, 132, 65)) + + bar: Type.String(), +>bar : Symbol(bar, Decl(deeplyNestedMappedTypes.ts, 61, 31)) +>Type.String : Symbol(Type.String, Decl(deeplyNestedMappedTypes.ts, 132, 65)) +>Type : Symbol(Type, Decl(deeplyNestedMappedTypes.ts, 129, 96)) +>String : Symbol(Type.String, Decl(deeplyNestedMappedTypes.ts, 132, 65)) + + }) + }) +}) + +function problematicFunction1(ors: Input[]): Output[] { +>problematicFunction1 : Symbol(problematicFunction1, Decl(deeplyNestedMappedTypes.ts, 65, 2)) +>ors : Symbol(ors, Decl(deeplyNestedMappedTypes.ts, 67, 30)) +>Input : Symbol(Input, Decl(deeplyNestedMappedTypes.ts, 44, 24), Decl(deeplyNestedMappedTypes.ts, 49, 12)) +>Output : Symbol(Output, Decl(deeplyNestedMappedTypes.ts, 55, 2), Decl(deeplyNestedMappedTypes.ts, 58, 12)) + + return ors; // Error +>ors : Symbol(ors, Decl(deeplyNestedMappedTypes.ts, 67, 30)) +} + +function problematicFunction2(ors: Input[]): T { +>problematicFunction2 : Symbol(problematicFunction2, Decl(deeplyNestedMappedTypes.ts, 69, 1)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 71, 30)) +>Output : Symbol(Output, Decl(deeplyNestedMappedTypes.ts, 55, 2), Decl(deeplyNestedMappedTypes.ts, 58, 12)) +>ors : Symbol(ors, Decl(deeplyNestedMappedTypes.ts, 71, 50)) +>Input : Symbol(Input, Decl(deeplyNestedMappedTypes.ts, 44, 24), Decl(deeplyNestedMappedTypes.ts, 49, 12)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 71, 30)) + + return ors; // Error +>ors : Symbol(ors, Decl(deeplyNestedMappedTypes.ts, 71, 50)) +} + +function problematicFunction3(ors: (typeof Input.static)[]): Output[] { +>problematicFunction3 : Symbol(problematicFunction3, Decl(deeplyNestedMappedTypes.ts, 73, 1)) +>ors : Symbol(ors, Decl(deeplyNestedMappedTypes.ts, 75, 30)) +>Input.static : Symbol(TObject.static, Decl(deeplyNestedMappedTypes.ts, 123, 20)) +>Input : Symbol(Input, Decl(deeplyNestedMappedTypes.ts, 44, 24), Decl(deeplyNestedMappedTypes.ts, 49, 12)) +>static : Symbol(TObject.static, Decl(deeplyNestedMappedTypes.ts, 123, 20)) +>Output : Symbol(Output, Decl(deeplyNestedMappedTypes.ts, 55, 2), Decl(deeplyNestedMappedTypes.ts, 58, 12)) + + return ors; // Error +>ors : Symbol(ors, Decl(deeplyNestedMappedTypes.ts, 75, 30)) +} + +export type Evaluate = T extends infer O ? { [K in keyof O]: O[K] } : never +>Evaluate : Symbol(Evaluate, Decl(deeplyNestedMappedTypes.ts, 77, 1)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 79, 21)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 79, 21)) +>O : Symbol(O, Decl(deeplyNestedMappedTypes.ts, 79, 41)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 79, 49)) +>O : Symbol(O, Decl(deeplyNestedMappedTypes.ts, 79, 41)) +>O : Symbol(O, Decl(deeplyNestedMappedTypes.ts, 79, 41)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 79, 49)) + +export declare const Readonly: unique symbol; +>Readonly : Symbol(Readonly, Decl(deeplyNestedMappedTypes.ts, 81, 20)) + +export declare const Optional: unique symbol; +>Optional : Symbol(Optional, Decl(deeplyNestedMappedTypes.ts, 82, 20)) + +export declare const Hint: unique symbol; +>Hint : Symbol(Hint, Decl(deeplyNestedMappedTypes.ts, 83, 20)) + +export declare const Kind: unique symbol; +>Kind : Symbol(Kind, Decl(deeplyNestedMappedTypes.ts, 84, 20)) + +export interface TKind { +>TKind : Symbol(TKind, Decl(deeplyNestedMappedTypes.ts, 84, 41)) + + [Kind]: string +>[Kind] : Symbol(TKind[Kind], Decl(deeplyNestedMappedTypes.ts, 86, 24)) +>Kind : Symbol(Kind, Decl(deeplyNestedMappedTypes.ts, 84, 20)) +} +export interface TSchema extends TKind { +>TSchema : Symbol(TSchema, Decl(deeplyNestedMappedTypes.ts, 88, 1)) +>TKind : Symbol(TKind, Decl(deeplyNestedMappedTypes.ts, 84, 41)) + + [Readonly]?: string +>[Readonly] : Symbol(TSchema[Readonly], Decl(deeplyNestedMappedTypes.ts, 89, 40)) +>Readonly : Symbol(Readonly, Decl(deeplyNestedMappedTypes.ts, 81, 20)) + + [Optional]?: string +>[Optional] : Symbol(TSchema[Optional], Decl(deeplyNestedMappedTypes.ts, 90, 23)) +>Optional : Symbol(Optional, Decl(deeplyNestedMappedTypes.ts, 82, 20)) + + [Hint]?: string +>[Hint] : Symbol(TSchema[Hint], Decl(deeplyNestedMappedTypes.ts, 91, 23)) +>Hint : Symbol(Hint, Decl(deeplyNestedMappedTypes.ts, 83, 20)) + + params: unknown[] +>params : Symbol(TSchema.params, Decl(deeplyNestedMappedTypes.ts, 92, 19)) + + static: unknown +>static : Symbol(TSchema.static, Decl(deeplyNestedMappedTypes.ts, 93, 21)) +} + +export type TReadonlyOptional = TOptional & TReadonly +>TReadonlyOptional : Symbol(TReadonlyOptional, Decl(deeplyNestedMappedTypes.ts, 95, 1)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 97, 30)) +>TSchema : Symbol(TSchema, Decl(deeplyNestedMappedTypes.ts, 88, 1)) +>TOptional : Symbol(TOptional, Decl(deeplyNestedMappedTypes.ts, 98, 73)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 97, 30)) +>TReadonly : Symbol(TReadonly, Decl(deeplyNestedMappedTypes.ts, 97, 78)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 97, 30)) + +export type TReadonly = T & { [Readonly]: 'Readonly' } +>TReadonly : Symbol(TReadonly, Decl(deeplyNestedMappedTypes.ts, 97, 78)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 98, 22)) +>TSchema : Symbol(TSchema, Decl(deeplyNestedMappedTypes.ts, 88, 1)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 98, 22)) +>[Readonly] : Symbol([Readonly], Decl(deeplyNestedMappedTypes.ts, 98, 48)) +>Readonly : Symbol(Readonly, Decl(deeplyNestedMappedTypes.ts, 81, 20)) + +export type TOptional = T & { [Optional]: 'Optional' } +>TOptional : Symbol(TOptional, Decl(deeplyNestedMappedTypes.ts, 98, 73)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 99, 22)) +>TSchema : Symbol(TSchema, Decl(deeplyNestedMappedTypes.ts, 88, 1)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 99, 22)) +>[Optional] : Symbol([Optional], Decl(deeplyNestedMappedTypes.ts, 99, 48)) +>Optional : Symbol(Optional, Decl(deeplyNestedMappedTypes.ts, 82, 20)) + +export interface TString extends TSchema { +>TString : Symbol(TString, Decl(deeplyNestedMappedTypes.ts, 99, 73)) +>TSchema : Symbol(TSchema, Decl(deeplyNestedMappedTypes.ts, 88, 1)) + + [Kind]: 'String'; +>[Kind] : Symbol(TString[Kind], Decl(deeplyNestedMappedTypes.ts, 101, 42)) +>Kind : Symbol(Kind, Decl(deeplyNestedMappedTypes.ts, 84, 20)) + + static: string; +>static : Symbol(TString.static, Decl(deeplyNestedMappedTypes.ts, 102, 21)) + + type: 'string'; +>type : Symbol(TString.type, Decl(deeplyNestedMappedTypes.ts, 103, 19)) +} + +export type ReadonlyOptionalPropertyKeys = { [K in keyof T]: T[K] extends TReadonly ? (T[K] extends TOptional ? K : never) : never }[keyof T] +>ReadonlyOptionalPropertyKeys : Symbol(ReadonlyOptionalPropertyKeys, Decl(deeplyNestedMappedTypes.ts, 105, 1)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 107, 41)) +>TProperties : Symbol(TProperties, Decl(deeplyNestedMappedTypes.ts, 120, 42)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 107, 69)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 107, 41)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 107, 41)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 107, 69)) +>TReadonly : Symbol(TReadonly, Decl(deeplyNestedMappedTypes.ts, 97, 78)) +>TSchema : Symbol(TSchema, Decl(deeplyNestedMappedTypes.ts, 88, 1)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 107, 41)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 107, 69)) +>TOptional : Symbol(TOptional, Decl(deeplyNestedMappedTypes.ts, 98, 73)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 107, 41)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 107, 69)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 107, 69)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 107, 41)) + +export type ReadonlyPropertyKeys = { [K in keyof T]: T[K] extends TReadonly ? (T[K] extends TOptional ? never : K) : never }[keyof T] +>ReadonlyPropertyKeys : Symbol(ReadonlyPropertyKeys, Decl(deeplyNestedMappedTypes.ts, 107, 179)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 108, 33)) +>TProperties : Symbol(TProperties, Decl(deeplyNestedMappedTypes.ts, 120, 42)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 108, 61)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 108, 33)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 108, 33)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 108, 61)) +>TReadonly : Symbol(TReadonly, Decl(deeplyNestedMappedTypes.ts, 97, 78)) +>TSchema : Symbol(TSchema, Decl(deeplyNestedMappedTypes.ts, 88, 1)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 108, 33)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 108, 61)) +>TOptional : Symbol(TOptional, Decl(deeplyNestedMappedTypes.ts, 98, 73)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 108, 33)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 108, 61)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 108, 61)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 108, 33)) + +export type OptionalPropertyKeys = { [K in keyof T]: T[K] extends TOptional ? (T[K] extends TReadonly ? never : K) : never }[keyof T] +>OptionalPropertyKeys : Symbol(OptionalPropertyKeys, Decl(deeplyNestedMappedTypes.ts, 108, 171)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 109, 33)) +>TProperties : Symbol(TProperties, Decl(deeplyNestedMappedTypes.ts, 120, 42)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 109, 61)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 109, 33)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 109, 33)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 109, 61)) +>TOptional : Symbol(TOptional, Decl(deeplyNestedMappedTypes.ts, 98, 73)) +>TSchema : Symbol(TSchema, Decl(deeplyNestedMappedTypes.ts, 88, 1)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 109, 33)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 109, 61)) +>TReadonly : Symbol(TReadonly, Decl(deeplyNestedMappedTypes.ts, 97, 78)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 109, 33)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 109, 61)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 109, 61)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 109, 33)) + +export type RequiredPropertyKeys = keyof Omit | ReadonlyPropertyKeys | OptionalPropertyKeys> +>RequiredPropertyKeys : Symbol(RequiredPropertyKeys, Decl(deeplyNestedMappedTypes.ts, 109, 171)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 110, 33)) +>TProperties : Symbol(TProperties, Decl(deeplyNestedMappedTypes.ts, 120, 42)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 110, 33)) +>ReadonlyOptionalPropertyKeys : Symbol(ReadonlyOptionalPropertyKeys, Decl(deeplyNestedMappedTypes.ts, 105, 1)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 110, 33)) +>ReadonlyPropertyKeys : Symbol(ReadonlyPropertyKeys, Decl(deeplyNestedMappedTypes.ts, 107, 179)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 110, 33)) +>OptionalPropertyKeys : Symbol(OptionalPropertyKeys, Decl(deeplyNestedMappedTypes.ts, 108, 171)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 110, 33)) + +export type PropertiesReducer> = Evaluate<( +>PropertiesReducer : Symbol(PropertiesReducer, Decl(deeplyNestedMappedTypes.ts, 110, 156)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 111, 30)) +>TProperties : Symbol(TProperties, Decl(deeplyNestedMappedTypes.ts, 120, 42)) +>R : Symbol(R, Decl(deeplyNestedMappedTypes.ts, 111, 52)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>Evaluate : Symbol(Evaluate, Decl(deeplyNestedMappedTypes.ts, 77, 1)) + + Readonly>>> & +>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>R : Symbol(R, Decl(deeplyNestedMappedTypes.ts, 111, 52)) +>ReadonlyOptionalPropertyKeys : Symbol(ReadonlyOptionalPropertyKeys, Decl(deeplyNestedMappedTypes.ts, 105, 1)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 111, 30)) + + Readonly>> & +>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>R : Symbol(R, Decl(deeplyNestedMappedTypes.ts, 111, 52)) +>ReadonlyPropertyKeys : Symbol(ReadonlyPropertyKeys, Decl(deeplyNestedMappedTypes.ts, 107, 179)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 111, 30)) + + Partial>> & +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>R : Symbol(R, Decl(deeplyNestedMappedTypes.ts, 111, 52)) +>OptionalPropertyKeys : Symbol(OptionalPropertyKeys, Decl(deeplyNestedMappedTypes.ts, 108, 171)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 111, 30)) + + Required>> +>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>R : Symbol(R, Decl(deeplyNestedMappedTypes.ts, 111, 52)) +>RequiredPropertyKeys : Symbol(RequiredPropertyKeys, Decl(deeplyNestedMappedTypes.ts, 109, 171)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 111, 30)) + +)> +export type PropertiesReduce = PropertiesReducerPropertiesReduce : Symbol(PropertiesReduce, Decl(deeplyNestedMappedTypes.ts, 116, 2)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 117, 29)) +>TProperties : Symbol(TProperties, Decl(deeplyNestedMappedTypes.ts, 120, 42)) +>P : Symbol(P, Decl(deeplyNestedMappedTypes.ts, 117, 51)) +>PropertiesReducer : Symbol(PropertiesReducer, Decl(deeplyNestedMappedTypes.ts, 110, 156)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 117, 29)) + + [K in keyof T]: Static +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 118, 5)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 117, 29)) +>Static : Symbol(Static, Decl(deeplyNestedMappedTypes.ts, 127, 1)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 117, 29)) +>K : Symbol(K, Decl(deeplyNestedMappedTypes.ts, 118, 5)) +>P : Symbol(P, Decl(deeplyNestedMappedTypes.ts, 117, 51)) + +}> +export type TPropertyKey = string | number +>TPropertyKey : Symbol(TPropertyKey, Decl(deeplyNestedMappedTypes.ts, 119, 2)) + +export type TProperties = Record +>TProperties : Symbol(TProperties, Decl(deeplyNestedMappedTypes.ts, 120, 42)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>TPropertyKey : Symbol(TPropertyKey, Decl(deeplyNestedMappedTypes.ts, 119, 2)) +>TSchema : Symbol(TSchema, Decl(deeplyNestedMappedTypes.ts, 88, 1)) + +export interface TObject extends TSchema { +>TObject : Symbol(TObject, Decl(deeplyNestedMappedTypes.ts, 121, 55)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 122, 25)) +>TProperties : Symbol(TProperties, Decl(deeplyNestedMappedTypes.ts, 120, 42)) +>TProperties : Symbol(TProperties, Decl(deeplyNestedMappedTypes.ts, 120, 42)) +>TSchema : Symbol(TSchema, Decl(deeplyNestedMappedTypes.ts, 88, 1)) + + [Kind]: 'Object' +>[Kind] : Symbol(TObject[Kind], Decl(deeplyNestedMappedTypes.ts, 122, 79)) +>Kind : Symbol(Kind, Decl(deeplyNestedMappedTypes.ts, 84, 20)) + + static: PropertiesReduce +>static : Symbol(TObject.static, Decl(deeplyNestedMappedTypes.ts, 123, 20)) +>PropertiesReduce : Symbol(PropertiesReduce, Decl(deeplyNestedMappedTypes.ts, 116, 2)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 122, 25)) + + type: 'object' +>type : Symbol(TObject.type, Decl(deeplyNestedMappedTypes.ts, 124, 47)) + + properties: T +>properties : Symbol(TObject.properties, Decl(deeplyNestedMappedTypes.ts, 125, 18)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 122, 25)) +} + +export type Static = (T & { params: P; })['static'] +>Static : Symbol(Static, Decl(deeplyNestedMappedTypes.ts, 127, 1)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 129, 19)) +>TSchema : Symbol(TSchema, Decl(deeplyNestedMappedTypes.ts, 88, 1)) +>P : Symbol(P, Decl(deeplyNestedMappedTypes.ts, 129, 37)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 129, 19)) +>params : Symbol(params, Decl(deeplyNestedMappedTypes.ts, 129, 72)) +>P : Symbol(P, Decl(deeplyNestedMappedTypes.ts, 129, 37)) + +declare namespace Type { +>Type : Symbol(Type, Decl(deeplyNestedMappedTypes.ts, 129, 96)) + + function Object(object: T): TObject +>Object : Symbol(Object, Decl(deeplyNestedMappedTypes.ts, 131, 24)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 132, 20)) +>TProperties : Symbol(TProperties, Decl(deeplyNestedMappedTypes.ts, 120, 42)) +>object : Symbol(object, Decl(deeplyNestedMappedTypes.ts, 132, 43)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 132, 20)) +>TObject : Symbol(TObject, Decl(deeplyNestedMappedTypes.ts, 121, 55)) +>T : Symbol(T, Decl(deeplyNestedMappedTypes.ts, 132, 20)) + + function String(): TString +>String : Symbol(String, Decl(deeplyNestedMappedTypes.ts, 132, 65)) +>TString : Symbol(TString, Decl(deeplyNestedMappedTypes.ts, 99, 73)) +} + diff --git a/tests/baselines/reference/deeplyNestedMappedTypes.types b/tests/baselines/reference/deeplyNestedMappedTypes.types index 2743fd69bf063..cbf3992088b54 100644 --- a/tests/baselines/reference/deeplyNestedMappedTypes.types +++ b/tests/baselines/reference/deeplyNestedMappedTypes.types @@ -125,3 +125,243 @@ const bar2: Bar2 = bar1; // Error expected >bar2 : { x: { y: { z: { a: { b: Record<"c", string>; }; }; }; }; } >bar1 : { x: { y: { z: { a: { b: Record<"c", number>; }; }; }; }; } +// Repro from #56138 + +export type Input = Static +>Input : { level1: { level2: { foo: string; }; }; } +>Input : TObject<{ level1: TObject<{ level2: TObject<{ foo: TString; }>; }>; }> + +export const Input = Type.Object({ +>Input : TObject<{ level1: TObject<{ level2: TObject<{ foo: TString; }>; }>; }> +>Type.Object({ level1: Type.Object({ level2: Type.Object({ foo: Type.String(), }) })}) : TObject<{ level1: TObject<{ level2: TObject<{ foo: TString; }>; }>; }> +>Type.Object : (object: T) => TObject +>Type : typeof Type +>Object : (object: T) => TObject +>{ level1: Type.Object({ level2: Type.Object({ foo: Type.String(), }) })} : { level1: TObject<{ level2: TObject<{ foo: TString; }>; }>; } + + level1: Type.Object({ +>level1 : TObject<{ level2: TObject<{ foo: TString; }>; }> +>Type.Object({ level2: Type.Object({ foo: Type.String(), }) }) : TObject<{ level2: TObject<{ foo: TString; }>; }> +>Type.Object : (object: T) => TObject +>Type : typeof Type +>Object : (object: T) => TObject +>{ level2: Type.Object({ foo: Type.String(), }) } : { level2: TObject<{ foo: TString; }>; } + + level2: Type.Object({ +>level2 : TObject<{ foo: TString; }> +>Type.Object({ foo: Type.String(), }) : TObject<{ foo: TString; }> +>Type.Object : (object: T) => TObject +>Type : typeof Type +>Object : (object: T) => TObject +>{ foo: Type.String(), } : { foo: TString; } + + foo: Type.String(), +>foo : TString +>Type.String() : TString +>Type.String : () => TString +>Type : typeof Type +>String : () => TString + + }) + }) +}) + +export type Output = Static +>Output : { level1: { level2: { foo: string; bar: string; }; }; } +>Output : TObject<{ level1: TObject<{ level2: TObject<{ foo: TString; bar: TString; }>; }>; }> + +export const Output = Type.Object({ +>Output : TObject<{ level1: TObject<{ level2: TObject<{ foo: TString; bar: TString; }>; }>; }> +>Type.Object({ level1: Type.Object({ level2: Type.Object({ foo: Type.String(), bar: Type.String(), }) })}) : TObject<{ level1: TObject<{ level2: TObject<{ foo: TString; bar: TString; }>; }>; }> +>Type.Object : (object: T) => TObject +>Type : typeof Type +>Object : (object: T) => TObject +>{ level1: Type.Object({ level2: Type.Object({ foo: Type.String(), bar: Type.String(), }) })} : { level1: TObject<{ level2: TObject<{ foo: TString; bar: TString; }>; }>; } + + level1: Type.Object({ +>level1 : TObject<{ level2: TObject<{ foo: TString; bar: TString; }>; }> +>Type.Object({ level2: Type.Object({ foo: Type.String(), bar: Type.String(), }) }) : TObject<{ level2: TObject<{ foo: TString; bar: TString; }>; }> +>Type.Object : (object: T) => TObject +>Type : typeof Type +>Object : (object: T) => TObject +>{ level2: Type.Object({ foo: Type.String(), bar: Type.String(), }) } : { level2: TObject<{ foo: TString; bar: TString; }>; } + + level2: Type.Object({ +>level2 : TObject<{ foo: TString; bar: TString; }> +>Type.Object({ foo: Type.String(), bar: Type.String(), }) : TObject<{ foo: TString; bar: TString; }> +>Type.Object : (object: T) => TObject +>Type : typeof Type +>Object : (object: T) => TObject +>{ foo: Type.String(), bar: Type.String(), } : { foo: TString; bar: TString; } + + foo: Type.String(), +>foo : TString +>Type.String() : TString +>Type.String : () => TString +>Type : typeof Type +>String : () => TString + + bar: Type.String(), +>bar : TString +>Type.String() : TString +>Type.String : () => TString +>Type : typeof Type +>String : () => TString + + }) + }) +}) + +function problematicFunction1(ors: Input[]): Output[] { +>problematicFunction1 : (ors: Input[]) => Output[] +>ors : { level1: { level2: { foo: string; }; }; }[] + + return ors; // Error +>ors : { level1: { level2: { foo: string; }; }; }[] +} + +function problematicFunction2(ors: Input[]): T { +>problematicFunction2 : (ors: Input[]) => T +>ors : { level1: { level2: { foo: string; }; }; }[] + + return ors; // Error +>ors : { level1: { level2: { foo: string; }; }; }[] +} + +function problematicFunction3(ors: (typeof Input.static)[]): Output[] { +>problematicFunction3 : (ors: (typeof Input.static)[]) => Output[] +>ors : { level1: { level2: { foo: string; }; }; }[] +>Input.static : { level1: { level2: { foo: string; }; }; } +>Input : TObject<{ level1: TObject<{ level2: TObject<{ foo: TString; }>; }>; }> +>static : { level1: { level2: { foo: string; }; }; } + + return ors; // Error +>ors : { level1: { level2: { foo: string; }; }; }[] +} + +export type Evaluate = T extends infer O ? { [K in keyof O]: O[K] } : never +>Evaluate : Evaluate + +export declare const Readonly: unique symbol; +>Readonly : unique symbol + +export declare const Optional: unique symbol; +>Optional : unique symbol + +export declare const Hint: unique symbol; +>Hint : unique symbol + +export declare const Kind: unique symbol; +>Kind : unique symbol + +export interface TKind { + [Kind]: string +>[Kind] : string +>Kind : unique symbol +} +export interface TSchema extends TKind { + [Readonly]?: string +>[Readonly] : string | undefined +>Readonly : unique symbol + + [Optional]?: string +>[Optional] : string | undefined +>Optional : unique symbol + + [Hint]?: string +>[Hint] : string | undefined +>Hint : unique symbol + + params: unknown[] +>params : unknown[] + + static: unknown +>static : unknown +} + +export type TReadonlyOptional = TOptional & TReadonly +>TReadonlyOptional : TReadonlyOptional + +export type TReadonly = T & { [Readonly]: 'Readonly' } +>TReadonly : TReadonly +>[Readonly] : "Readonly" +>Readonly : unique symbol + +export type TOptional = T & { [Optional]: 'Optional' } +>TOptional : TOptional +>[Optional] : "Optional" +>Optional : unique symbol + +export interface TString extends TSchema { + [Kind]: 'String'; +>[Kind] : "String" +>Kind : unique symbol + + static: string; +>static : string + + type: 'string'; +>type : "string" +} + +export type ReadonlyOptionalPropertyKeys = { [K in keyof T]: T[K] extends TReadonly ? (T[K] extends TOptional ? K : never) : never }[keyof T] +>ReadonlyOptionalPropertyKeys : ReadonlyOptionalPropertyKeys + +export type ReadonlyPropertyKeys = { [K in keyof T]: T[K] extends TReadonly ? (T[K] extends TOptional ? never : K) : never }[keyof T] +>ReadonlyPropertyKeys : ReadonlyPropertyKeys + +export type OptionalPropertyKeys = { [K in keyof T]: T[K] extends TOptional ? (T[K] extends TReadonly ? never : K) : never }[keyof T] +>OptionalPropertyKeys : OptionalPropertyKeys + +export type RequiredPropertyKeys = keyof Omit | ReadonlyPropertyKeys | OptionalPropertyKeys> +>RequiredPropertyKeys : Exclude | ReadonlyPropertyKeys | OptionalPropertyKeys> + +export type PropertiesReducer> = Evaluate<( +>PropertiesReducer : PropertiesReducer + + Readonly>>> & + Readonly>> & + Partial>> & + Required>> +)> +export type PropertiesReduce = PropertiesReducerPropertiesReduce : PropertiesReduce + + [K in keyof T]: Static +}> +export type TPropertyKey = string | number +>TPropertyKey : string | number + +export type TProperties = Record +>TProperties : { [x: string]: TSchema; [x: number]: TSchema; } + +export interface TObject extends TSchema { + [Kind]: 'Object' +>[Kind] : "Object" +>Kind : unique symbol + + static: PropertiesReduce +>static : Evaluate; }, ReadonlyOptionalPropertyKeys>>> & Readonly; }, ReadonlyPropertyKeys>> & Partial; }, OptionalPropertyKeys>> & Required; }, Exclude | ReadonlyPropertyKeys | OptionalPropertyKeys>>>> + + type: 'object' +>type : "object" + + properties: T +>properties : T +} + +export type Static = (T & { params: P; })['static'] +>Static : Static +>params : P + +declare namespace Type { +>Type : typeof Type + + function Object(object: T): TObject +>Object : (object: T) => TObject +>object : T + + function String(): TString +>String : () => TString +} + diff --git a/tests/cases/compiler/deeplyNestedMappedTypes.ts b/tests/cases/compiler/deeplyNestedMappedTypes.ts index 6c368e3026b28..d758f17d06940 100644 --- a/tests/cases/compiler/deeplyNestedMappedTypes.ts +++ b/tests/cases/compiler/deeplyNestedMappedTypes.ts @@ -46,3 +46,93 @@ type Bar2 = NestedRecord<"x.y.z.a.b.c", string>; declare const bar1: Bar1; const bar2: Bar2 = bar1; // Error expected + +// Repro from #56138 + +export type Input = Static +export const Input = Type.Object({ + level1: Type.Object({ + level2: Type.Object({ + foo: Type.String(), + }) + }) +}) + +export type Output = Static +export const Output = Type.Object({ + level1: Type.Object({ + level2: Type.Object({ + foo: Type.String(), + bar: Type.String(), + }) + }) +}) + +function problematicFunction1(ors: Input[]): Output[] { + return ors; // Error +} + +function problematicFunction2(ors: Input[]): T { + return ors; // Error +} + +function problematicFunction3(ors: (typeof Input.static)[]): Output[] { + return ors; // Error +} + +export type Evaluate = T extends infer O ? { [K in keyof O]: O[K] } : never + +export declare const Readonly: unique symbol; +export declare const Optional: unique symbol; +export declare const Hint: unique symbol; +export declare const Kind: unique symbol; + +export interface TKind { + [Kind]: string +} +export interface TSchema extends TKind { + [Readonly]?: string + [Optional]?: string + [Hint]?: string + params: unknown[] + static: unknown +} + +export type TReadonlyOptional = TOptional & TReadonly +export type TReadonly = T & { [Readonly]: 'Readonly' } +export type TOptional = T & { [Optional]: 'Optional' } + +export interface TString extends TSchema { + [Kind]: 'String'; + static: string; + type: 'string'; +} + +export type ReadonlyOptionalPropertyKeys = { [K in keyof T]: T[K] extends TReadonly ? (T[K] extends TOptional ? K : never) : never }[keyof T] +export type ReadonlyPropertyKeys = { [K in keyof T]: T[K] extends TReadonly ? (T[K] extends TOptional ? never : K) : never }[keyof T] +export type OptionalPropertyKeys = { [K in keyof T]: T[K] extends TOptional ? (T[K] extends TReadonly ? never : K) : never }[keyof T] +export type RequiredPropertyKeys = keyof Omit | ReadonlyPropertyKeys | OptionalPropertyKeys> +export type PropertiesReducer> = Evaluate<( + Readonly>>> & + Readonly>> & + Partial>> & + Required>> +)> +export type PropertiesReduce = PropertiesReducer +}> +export type TPropertyKey = string | number +export type TProperties = Record +export interface TObject extends TSchema { + [Kind]: 'Object' + static: PropertiesReduce + type: 'object' + properties: T +} + +export type Static = (T & { params: P; })['static'] + +declare namespace Type { + function Object(object: T): TObject + function String(): TString +}