Improve isDeeplyNestedType for homomorphic mapped types (#56169)

This commit is contained in:
Anders Hejlsberg 2023-10-23 08:53:46 -07:00 committed by GitHub
parent 8af8f3c4d1
commit b76b4c26ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 875 additions and 37 deletions

View File

@ -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<T> = null extends T ? [A<NonNullable<T>>] : [T]`
// has expanded into `[A<NonNullable<NonNullable<NonNullable<NonNullable<NonNullable<T>>>>>>]`. 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<T> = { next: Deep<Deep<T>> }`, 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;
}

View File

@ -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<T> = { [K in keyof T]: Id<T[K]> };
@ -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<typeof Input>
export const Input = Type.Object({
level1: Type.Object({
level2: Type.Object({
foo: Type.String(),
})
})
})
export type Output = Static<typeof Output>
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<T extends Output[]>(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> = 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<T extends TSchema> = TOptional<T> & TReadonly<T>
export type TReadonly<T extends TSchema> = T & { [Readonly]: 'Readonly' }
export type TOptional<T extends TSchema> = T & { [Optional]: 'Optional' }
export interface TString extends TSchema {
[Kind]: 'String';
static: string;
type: 'string';
}
export type ReadonlyOptionalPropertyKeys<T extends TProperties> = { [K in keyof T]: T[K] extends TReadonly<TSchema> ? (T[K] extends TOptional<T[K]> ? K : never) : never }[keyof T]
export type ReadonlyPropertyKeys<T extends TProperties> = { [K in keyof T]: T[K] extends TReadonly<TSchema> ? (T[K] extends TOptional<T[K]> ? never : K) : never }[keyof T]
export type OptionalPropertyKeys<T extends TProperties> = { [K in keyof T]: T[K] extends TOptional<TSchema> ? (T[K] extends TReadonly<T[K]> ? never : K) : never }[keyof T]
export type RequiredPropertyKeys<T extends TProperties> = keyof Omit<T, ReadonlyOptionalPropertyKeys<T> | ReadonlyPropertyKeys<T> | OptionalPropertyKeys<T>>
export type PropertiesReducer<T extends TProperties, R extends Record<keyof any, unknown>> = Evaluate<(
Readonly<Partial<Pick<R, ReadonlyOptionalPropertyKeys<T>>>> &
Readonly<Pick<R, ReadonlyPropertyKeys<T>>> &
Partial<Pick<R, OptionalPropertyKeys<T>>> &
Required<Pick<R, RequiredPropertyKeys<T>>>
)>
export type PropertiesReduce<T extends TProperties, P extends unknown[]> = PropertiesReducer<T, {
[K in keyof T]: Static<T[K], P>
}>
export type TPropertyKey = string | number
export type TProperties = Record<TPropertyKey, TSchema>
export interface TObject<T extends TProperties = TProperties> extends TSchema {
[Kind]: 'Object'
static: PropertiesReduce<T, this['params']>
type: 'object'
properties: T
}
export type Static<T extends TSchema, P extends unknown[] = []> = (T & { params: P; })['static']
declare namespace Type {
function Object<T extends TProperties>(object: T): TObject<T>
function String(): TString
}

View File

@ -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<typeof Input>
>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<typeof Output>
>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<T extends Output[]>(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> = 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<T extends TSchema> = TOptional<T> & TReadonly<T>
>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 extends TSchema> = 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 extends TSchema> = 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<T extends TProperties> = { [K in keyof T]: T[K] extends TReadonly<TSchema> ? (T[K] extends TOptional<T[K]> ? 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<T extends TProperties> = { [K in keyof T]: T[K] extends TReadonly<TSchema> ? (T[K] extends TOptional<T[K]> ? 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<T extends TProperties> = { [K in keyof T]: T[K] extends TOptional<TSchema> ? (T[K] extends TReadonly<T[K]> ? 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<T extends TProperties> = keyof Omit<T, ReadonlyOptionalPropertyKeys<T> | ReadonlyPropertyKeys<T> | OptionalPropertyKeys<T>>
>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<T extends TProperties, R extends Record<keyof any, unknown>> = 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<Partial<Pick<R, ReadonlyOptionalPropertyKeys<T>>>> &
>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<Pick<R, ReadonlyPropertyKeys<T>>> &
>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<Pick<R, OptionalPropertyKeys<T>>> &
>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<Pick<R, RequiredPropertyKeys<T>>>
>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<T extends TProperties, P extends unknown[]> = PropertiesReducer<T, {
>PropertiesReduce : 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<T[K], P>
>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<TPropertyKey, TSchema>
>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<T extends TProperties = TProperties> 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<T, this['params']>
>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 extends TSchema, P extends unknown[] = []> = (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<T extends TProperties>(object: T): TObject<T>
>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))
}

View File

@ -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<typeof Input>
>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 : <T extends TProperties>(object: T) => TObject<T>
>Type : typeof Type
>Object : <T extends TProperties>(object: T) => TObject<T>
>{ 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 : <T extends TProperties>(object: T) => TObject<T>
>Type : typeof Type
>Object : <T extends TProperties>(object: T) => TObject<T>
>{ 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 : <T extends TProperties>(object: T) => TObject<T>
>Type : typeof Type
>Object : <T extends TProperties>(object: T) => TObject<T>
>{ 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<typeof Output>
>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 : <T extends TProperties>(object: T) => TObject<T>
>Type : typeof Type
>Object : <T extends TProperties>(object: T) => TObject<T>
>{ 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 : <T extends TProperties>(object: T) => TObject<T>
>Type : typeof Type
>Object : <T extends TProperties>(object: T) => TObject<T>
>{ 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 : <T extends TProperties>(object: T) => TObject<T>
>Type : typeof Type
>Object : <T extends TProperties>(object: T) => TObject<T>
>{ 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<T extends Output[]>(ors: Input[]): T {
>problematicFunction2 : <T extends { level1: { level2: { foo: string; bar: string; }; }; }[]>(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> = T extends infer O ? { [K in keyof O]: O[K] } : never
>Evaluate : Evaluate<T>
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<T extends TSchema> = TOptional<T> & TReadonly<T>
>TReadonlyOptional : TReadonlyOptional<T>
export type TReadonly<T extends TSchema> = T & { [Readonly]: 'Readonly' }
>TReadonly : TReadonly<T>
>[Readonly] : "Readonly"
>Readonly : unique symbol
export type TOptional<T extends TSchema> = T & { [Optional]: 'Optional' }
>TOptional : TOptional<T>
>[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<T extends TProperties> = { [K in keyof T]: T[K] extends TReadonly<TSchema> ? (T[K] extends TOptional<T[K]> ? K : never) : never }[keyof T]
>ReadonlyOptionalPropertyKeys : ReadonlyOptionalPropertyKeys<T>
export type ReadonlyPropertyKeys<T extends TProperties> = { [K in keyof T]: T[K] extends TReadonly<TSchema> ? (T[K] extends TOptional<T[K]> ? never : K) : never }[keyof T]
>ReadonlyPropertyKeys : ReadonlyPropertyKeys<T>
export type OptionalPropertyKeys<T extends TProperties> = { [K in keyof T]: T[K] extends TOptional<TSchema> ? (T[K] extends TReadonly<T[K]> ? never : K) : never }[keyof T]
>OptionalPropertyKeys : OptionalPropertyKeys<T>
export type RequiredPropertyKeys<T extends TProperties> = keyof Omit<T, ReadonlyOptionalPropertyKeys<T> | ReadonlyPropertyKeys<T> | OptionalPropertyKeys<T>>
>RequiredPropertyKeys : Exclude<keyof T, ReadonlyOptionalPropertyKeys<T> | ReadonlyPropertyKeys<T> | OptionalPropertyKeys<T>>
export type PropertiesReducer<T extends TProperties, R extends Record<keyof any, unknown>> = Evaluate<(
>PropertiesReducer : PropertiesReducer<T, R>
Readonly<Partial<Pick<R, ReadonlyOptionalPropertyKeys<T>>>> &
Readonly<Pick<R, ReadonlyPropertyKeys<T>>> &
Partial<Pick<R, OptionalPropertyKeys<T>>> &
Required<Pick<R, RequiredPropertyKeys<T>>>
)>
export type PropertiesReduce<T extends TProperties, P extends unknown[]> = PropertiesReducer<T, {
>PropertiesReduce : PropertiesReduce<T, P>
[K in keyof T]: Static<T[K], P>
}>
export type TPropertyKey = string | number
>TPropertyKey : string | number
export type TProperties = Record<TPropertyKey, TSchema>
>TProperties : { [x: string]: TSchema; [x: number]: TSchema; }
export interface TObject<T extends TProperties = TProperties> extends TSchema {
[Kind]: 'Object'
>[Kind] : "Object"
>Kind : unique symbol
static: PropertiesReduce<T, this['params']>
>static : Evaluate<Readonly<Partial<Pick<{ [K in keyof T]: Static<T[K], this["params"]>; }, ReadonlyOptionalPropertyKeys<T>>>> & Readonly<Pick<{ [K in keyof T]: Static<T[K], this["params"]>; }, ReadonlyPropertyKeys<T>>> & Partial<Pick<{ [K in keyof T]: Static<T[K], this["params"]>; }, OptionalPropertyKeys<T>>> & Required<Pick<{ [K in keyof T]: Static<T[K], this["params"]>; }, Exclude<keyof T, ReadonlyOptionalPropertyKeys<T> | ReadonlyPropertyKeys<T> | OptionalPropertyKeys<T>>>>>
type: 'object'
>type : "object"
properties: T
>properties : T
}
export type Static<T extends TSchema, P extends unknown[] = []> = (T & { params: P; })['static']
>Static : Static<T, P>
>params : P
declare namespace Type {
>Type : typeof Type
function Object<T extends TProperties>(object: T): TObject<T>
>Object : <T extends TProperties>(object: T) => TObject<T>
>object : T
function String(): TString
>String : () => TString
}

View File

@ -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<typeof Input>
export const Input = Type.Object({
level1: Type.Object({
level2: Type.Object({
foo: Type.String(),
})
})
})
export type Output = Static<typeof Output>
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<T extends Output[]>(ors: Input[]): T {
return ors; // Error
}
function problematicFunction3(ors: (typeof Input.static)[]): Output[] {
return ors; // Error
}
export type Evaluate<T> = 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<T extends TSchema> = TOptional<T> & TReadonly<T>
export type TReadonly<T extends TSchema> = T & { [Readonly]: 'Readonly' }
export type TOptional<T extends TSchema> = T & { [Optional]: 'Optional' }
export interface TString extends TSchema {
[Kind]: 'String';
static: string;
type: 'string';
}
export type ReadonlyOptionalPropertyKeys<T extends TProperties> = { [K in keyof T]: T[K] extends TReadonly<TSchema> ? (T[K] extends TOptional<T[K]> ? K : never) : never }[keyof T]
export type ReadonlyPropertyKeys<T extends TProperties> = { [K in keyof T]: T[K] extends TReadonly<TSchema> ? (T[K] extends TOptional<T[K]> ? never : K) : never }[keyof T]
export type OptionalPropertyKeys<T extends TProperties> = { [K in keyof T]: T[K] extends TOptional<TSchema> ? (T[K] extends TReadonly<T[K]> ? never : K) : never }[keyof T]
export type RequiredPropertyKeys<T extends TProperties> = keyof Omit<T, ReadonlyOptionalPropertyKeys<T> | ReadonlyPropertyKeys<T> | OptionalPropertyKeys<T>>
export type PropertiesReducer<T extends TProperties, R extends Record<keyof any, unknown>> = Evaluate<(
Readonly<Partial<Pick<R, ReadonlyOptionalPropertyKeys<T>>>> &
Readonly<Pick<R, ReadonlyPropertyKeys<T>>> &
Partial<Pick<R, OptionalPropertyKeys<T>>> &
Required<Pick<R, RequiredPropertyKeys<T>>>
)>
export type PropertiesReduce<T extends TProperties, P extends unknown[]> = PropertiesReducer<T, {
[K in keyof T]: Static<T[K], P>
}>
export type TPropertyKey = string | number
export type TProperties = Record<TPropertyKey, TSchema>
export interface TObject<T extends TProperties = TProperties> extends TSchema {
[Kind]: 'Object'
static: PropertiesReduce<T, this['params']>
type: 'object'
properties: T
}
export type Static<T extends TSchema, P extends unknown[] = []> = (T & { params: P; })['static']
declare namespace Type {
function Object<T extends TProperties>(object: T): TObject<T>
function String(): TString
}