Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Avoid resolving source prop type when the target is unknown/any #61660

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24057,6 +24057,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function isPropertySymbolTypeRelated(sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
const targetIsOptional = strictNullChecks && !!(getCheckFlags(targetProp) & CheckFlags.Partial);
const effectiveTarget = addOptionality(getNonMissingTypeOfSymbol(targetProp), /*isProperty*/ false, targetIsOptional);
// source could resolve to `any` and that's not related to `unknown` target under strict subtype relation
if (effectiveTarget.flags & (relation === strictSubtypeRelation ? TypeFlags.Any : TypeFlags.AnyOrUnknown)) {
Copy link
Preview

Copilot AI May 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition now short-circuits the type relation check when the target type is 'any' (or 'any'/'unknown' depending on the relation), which is the intended behavior per issue #61659. Consider adding a reference to the issue number in the comment for clearer context and future maintainability.

Copilot uses AI. Check for mistakes.

return Ternary.True;
}
const effectiveSource = getTypeOfSourceProperty(sourceProp);
return isRelatedTo(effectiveSource, effectiveTarget, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
}
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/multiline.types
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

=== Performance Stats ===
Type Count: 2,500
Instantiation count: 2,500
Instantiation count: 1,000

=== a.ts ===
export const texts: string[] = [];
Expand Down
142 changes: 142 additions & 0 deletions tests/baselines/reference/noCircularitySelfReferentialGetter1.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//// [tests/cases/compiler/noCircularitySelfReferentialGetter1.ts] ////

=== noCircularitySelfReferentialGetter1.ts ===
// https://github.com/microsoft/TypeScript/issues/61659

interface ZodType {
>ZodType : Symbol(ZodType, Decl(noCircularitySelfReferentialGetter1.ts, 0, 0))

optional: "true" | "false";
>optional : Symbol(ZodType.optional, Decl(noCircularitySelfReferentialGetter1.ts, 2, 19))

output: any;
>output : Symbol(ZodType.output, Decl(noCircularitySelfReferentialGetter1.ts, 3, 29))
}

interface ZodString extends ZodType {
>ZodString : Symbol(ZodString, Decl(noCircularitySelfReferentialGetter1.ts, 5, 1))
>ZodType : Symbol(ZodType, Decl(noCircularitySelfReferentialGetter1.ts, 0, 0))

optional: "false";
>optional : Symbol(ZodString.optional, Decl(noCircularitySelfReferentialGetter1.ts, 7, 37))

output: string;
>output : Symbol(ZodString.output, Decl(noCircularitySelfReferentialGetter1.ts, 8, 20))
}

type ZodShape = Record<string, any>;
>ZodShape : Symbol(ZodShape, Decl(noCircularitySelfReferentialGetter1.ts, 10, 1))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))

type Prettify<T> = { [K in keyof T]: T[K] } & {};
>Prettify : Symbol(Prettify, Decl(noCircularitySelfReferentialGetter1.ts, 12, 36))
>T : Symbol(T, Decl(noCircularitySelfReferentialGetter1.ts, 13, 14))
>K : Symbol(K, Decl(noCircularitySelfReferentialGetter1.ts, 13, 22))
>T : Symbol(T, Decl(noCircularitySelfReferentialGetter1.ts, 13, 14))
>T : Symbol(T, Decl(noCircularitySelfReferentialGetter1.ts, 13, 14))
>K : Symbol(K, Decl(noCircularitySelfReferentialGetter1.ts, 13, 22))

type InferObjectType<Shape extends ZodShape> = Prettify<
>InferObjectType : Symbol(InferObjectType, Decl(noCircularitySelfReferentialGetter1.ts, 13, 49))
>Shape : Symbol(Shape, Decl(noCircularitySelfReferentialGetter1.ts, 14, 21))
>ZodShape : Symbol(ZodShape, Decl(noCircularitySelfReferentialGetter1.ts, 10, 1))
>Prettify : Symbol(Prettify, Decl(noCircularitySelfReferentialGetter1.ts, 12, 36))
{
[k in keyof Shape as Shape[k] extends { optional: "true" }
>k : Symbol(k, Decl(noCircularitySelfReferentialGetter1.ts, 16, 5))
>Shape : Symbol(Shape, Decl(noCircularitySelfReferentialGetter1.ts, 14, 21))
>Shape : Symbol(Shape, Decl(noCircularitySelfReferentialGetter1.ts, 14, 21))
>k : Symbol(k, Decl(noCircularitySelfReferentialGetter1.ts, 16, 5))
>optional : Symbol(optional, Decl(noCircularitySelfReferentialGetter1.ts, 16, 43))

? k
>k : Symbol(k, Decl(noCircularitySelfReferentialGetter1.ts, 16, 5))

: never]?: Shape[k]["output"];
>Shape : Symbol(Shape, Decl(noCircularitySelfReferentialGetter1.ts, 14, 21))
>k : Symbol(k, Decl(noCircularitySelfReferentialGetter1.ts, 16, 5))

} & {
[k in keyof Shape as Shape[k] extends { optional: "true" }
>k : Symbol(k, Decl(noCircularitySelfReferentialGetter1.ts, 20, 5))
>Shape : Symbol(Shape, Decl(noCircularitySelfReferentialGetter1.ts, 14, 21))
>Shape : Symbol(Shape, Decl(noCircularitySelfReferentialGetter1.ts, 14, 21))
>k : Symbol(k, Decl(noCircularitySelfReferentialGetter1.ts, 20, 5))
>optional : Symbol(optional, Decl(noCircularitySelfReferentialGetter1.ts, 20, 43))

? never
: k]: Shape[k]["output"];
>k : Symbol(k, Decl(noCircularitySelfReferentialGetter1.ts, 20, 5))
>Shape : Symbol(Shape, Decl(noCircularitySelfReferentialGetter1.ts, 14, 21))
>k : Symbol(k, Decl(noCircularitySelfReferentialGetter1.ts, 20, 5))
}
>;
interface ZodObject<T extends ZodShape> extends ZodType {
>ZodObject : Symbol(ZodObject, Decl(noCircularitySelfReferentialGetter1.ts, 24, 2))
>T : Symbol(T, Decl(noCircularitySelfReferentialGetter1.ts, 25, 20))
>ZodShape : Symbol(ZodShape, Decl(noCircularitySelfReferentialGetter1.ts, 10, 1))
>ZodType : Symbol(ZodType, Decl(noCircularitySelfReferentialGetter1.ts, 0, 0))

optional: "false";
>optional : Symbol(ZodObject.optional, Decl(noCircularitySelfReferentialGetter1.ts, 25, 57))

output: InferObjectType<T>;
>output : Symbol(ZodObject.output, Decl(noCircularitySelfReferentialGetter1.ts, 26, 20))
>InferObjectType : Symbol(InferObjectType, Decl(noCircularitySelfReferentialGetter1.ts, 13, 49))
>T : Symbol(T, Decl(noCircularitySelfReferentialGetter1.ts, 25, 20))
}

interface ZodOptional<T extends ZodType> extends ZodType {
>ZodOptional : Symbol(ZodOptional, Decl(noCircularitySelfReferentialGetter1.ts, 28, 1))
>T : Symbol(T, Decl(noCircularitySelfReferentialGetter1.ts, 30, 22))
>ZodType : Symbol(ZodType, Decl(noCircularitySelfReferentialGetter1.ts, 0, 0))
>ZodType : Symbol(ZodType, Decl(noCircularitySelfReferentialGetter1.ts, 0, 0))

optional: "true";
>optional : Symbol(ZodOptional.optional, Decl(noCircularitySelfReferentialGetter1.ts, 30, 58))

output: T["output"] | undefined;
>output : Symbol(ZodOptional.output, Decl(noCircularitySelfReferentialGetter1.ts, 31, 19))
>T : Symbol(T, Decl(noCircularitySelfReferentialGetter1.ts, 30, 22))
}

declare function object<T extends ZodShape>(shape: T): ZodObject<T>;
>object : Symbol(object, Decl(noCircularitySelfReferentialGetter1.ts, 33, 1))
>T : Symbol(T, Decl(noCircularitySelfReferentialGetter1.ts, 35, 24))
>ZodShape : Symbol(ZodShape, Decl(noCircularitySelfReferentialGetter1.ts, 10, 1))
>shape : Symbol(shape, Decl(noCircularitySelfReferentialGetter1.ts, 35, 44))
>T : Symbol(T, Decl(noCircularitySelfReferentialGetter1.ts, 35, 24))
>ZodObject : Symbol(ZodObject, Decl(noCircularitySelfReferentialGetter1.ts, 24, 2))
>T : Symbol(T, Decl(noCircularitySelfReferentialGetter1.ts, 35, 24))

declare function string(): ZodString;
>string : Symbol(string, Decl(noCircularitySelfReferentialGetter1.ts, 35, 68))
>ZodString : Symbol(ZodString, Decl(noCircularitySelfReferentialGetter1.ts, 5, 1))

declare function optional<T extends ZodType>(schema: T): ZodOptional<T>;
>optional : Symbol(optional, Decl(noCircularitySelfReferentialGetter1.ts, 36, 37))
>T : Symbol(T, Decl(noCircularitySelfReferentialGetter1.ts, 37, 26))
>ZodType : Symbol(ZodType, Decl(noCircularitySelfReferentialGetter1.ts, 0, 0))
>schema : Symbol(schema, Decl(noCircularitySelfReferentialGetter1.ts, 37, 45))
>T : Symbol(T, Decl(noCircularitySelfReferentialGetter1.ts, 37, 26))
>ZodOptional : Symbol(ZodOptional, Decl(noCircularitySelfReferentialGetter1.ts, 28, 1))
>T : Symbol(T, Decl(noCircularitySelfReferentialGetter1.ts, 37, 26))

const Category = object({
>Category : Symbol(Category, Decl(noCircularitySelfReferentialGetter1.ts, 39, 5))
>object : Symbol(object, Decl(noCircularitySelfReferentialGetter1.ts, 33, 1))

name: string(),
>name : Symbol(name, Decl(noCircularitySelfReferentialGetter1.ts, 39, 25))
>string : Symbol(string, Decl(noCircularitySelfReferentialGetter1.ts, 35, 68))

get parent() {
>parent : Symbol(parent, Decl(noCircularitySelfReferentialGetter1.ts, 40, 17))

return optional(Category);
>optional : Symbol(optional, Decl(noCircularitySelfReferentialGetter1.ts, 36, 37))
>Category : Symbol(Category, Decl(noCircularitySelfReferentialGetter1.ts, 39, 5))

},
});

120 changes: 120 additions & 0 deletions tests/baselines/reference/noCircularitySelfReferentialGetter1.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//// [tests/cases/compiler/noCircularitySelfReferentialGetter1.ts] ////

=== noCircularitySelfReferentialGetter1.ts ===
// https://github.com/microsoft/TypeScript/issues/61659

interface ZodType {
optional: "true" | "false";
>optional : "true" | "false"
> : ^^^^^^^^^^^^^^^^

output: any;
>output : any
}

interface ZodString extends ZodType {
optional: "false";
>optional : "false"
> : ^^^^^^^

output: string;
>output : string
> : ^^^^^^
}

type ZodShape = Record<string, any>;
>ZodShape : ZodShape
> : ^^^^^^^^

type Prettify<T> = { [K in keyof T]: T[K] } & {};
>Prettify : { [K in keyof T]: T[K]; }
> : ^^^ ^^^^^^^^^^^^^^^^^^^^^

type InferObjectType<Shape extends ZodShape> = Prettify<
>InferObjectType : { [k in keyof Shape as Shape[k] extends { optional: "true"; } ? k : never]?: Shape[k]["output"] | undefined; } & { [k_1 in keyof Shape as Shape[k_1] extends { optional: "true"; } ? never : k_1]: Shape[k_1]["output"]; } extends infer T ? { [K in keyof T]: ({ [k in keyof Shape as Shape[k] extends { optional: "true"; } ? k : never]?: Shape[k]["output"] | undefined; } & { [k_1 in keyof Shape as Shape[k_1] extends { optional: "true"; } ? never : k_1]: Shape[k_1]["output"]; })[K]; } : never
> : ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
[k in keyof Shape as Shape[k] extends { optional: "true" }
>optional : "true"
> : ^^^^^^

? k
: never]?: Shape[k]["output"];
} & {
[k in keyof Shape as Shape[k] extends { optional: "true" }
>optional : "true"
> : ^^^^^^

? never
: k]: Shape[k]["output"];
}
>;
interface ZodObject<T extends ZodShape> extends ZodType {
optional: "false";
>optional : "false"
> : ^^^^^^^

output: InferObjectType<T>;
>output : { [k in keyof T as T[k] extends { optional: "true"; } ? k : never]?: T[k]["output"] | undefined; } & { [k_1 in keyof T as T[k_1] extends { optional: "true"; } ? never : k_1]: T[k_1]["output"]; } extends infer T_1 ? { [K in keyof T_1]: ({ [k in keyof T as T[k] extends { optional: "true"; } ? k : never]?: T[k]["output"] | undefined; } & { [k_1 in keyof T as T[k_1] extends { optional: "true"; } ? never : k_1]: T[k_1]["output"]; })[K]; } : never
> : ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}

interface ZodOptional<T extends ZodType> extends ZodType {
optional: "true";
>optional : "true"
> : ^^^^^^

output: T["output"] | undefined;
>output : T["output"] | undefined
> : ^^^^^^^^^^^^^^^^^^^^^^^
}

declare function object<T extends ZodShape>(shape: T): ZodObject<T>;
>object : <T extends ZodShape>(shape: T) => ZodObject<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>shape : T
> : ^

declare function string(): ZodString;
>string : () => ZodString
> : ^^^^^^

declare function optional<T extends ZodType>(schema: T): ZodOptional<T>;
>optional : <T extends ZodType>(schema: T) => ZodOptional<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>schema : T
> : ^

const Category = object({
>Category : ZodObject<{ name: ZodString; readonly parent: ZodOptional<ZodObject<any>>; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>object({ name: string(), get parent() { return optional(Category); },}) : ZodObject<{ name: ZodString; readonly parent: ZodOptional<ZodObject<any>>; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>object : <T extends ZodShape>(shape: T) => ZodObject<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>{ name: string(), get parent() { return optional(Category); },} : { name: ZodString; readonly parent: ZodOptional<ZodObject<{ name: ZodString; readonly parent: ZodOptional<ZodObject<any>>; }>>; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

name: string(),
>name : ZodString
> : ^^^^^^^^^
>string() : ZodString
> : ^^^^^^^^^
>string : () => ZodString
> : ^^^^^^

get parent() {
>parent : ZodOptional<ZodObject<{ name: ZodString; readonly parent: ZodOptional<ZodObject<any>>; }>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

return optional(Category);
>optional(Category) : ZodOptional<ZodObject<{ name: ZodString; readonly parent: ZodOptional<ZodObject<any>>; }>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>optional : <T extends ZodType>(schema: T) => ZodOptional<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>Category : ZodObject<{ name: ZodString; readonly parent: ZodOptional<ZodObject<any>>; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

},
});

Loading