Skip to content
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

Unresolved generic type arguments end up in type declarations since 5.7.2 #61338

Open
AlCalzone opened this issue Mar 3, 2025 · 0 comments
Open

Comments

@AlCalzone
Copy link
Contributor

AlCalzone commented Mar 3, 2025

🔎 Search Terms

unresolved, undefined, declarations

🕗 Version & Regression Information

  • This changed between versions 5.6.3 and 5.7.2

In a project, I have a relatively complex set of generic types to be able to declare some values that get expanded and merged with defaults at runtime, while exposing that behavior in the type system. This seems to be complex enough that the semantic highlighting in VSCode regularly breaks in that file: https://github.com/zwave-js/zwave-js/blob/133172125d4148ea6e9e92a059b4325862ff6dd7/packages/cc/src/lib/Values.ts

Until TS 5.6.3, this code

export const BasicCCValues = Object.freeze({
	...V.defineStaticCCValues(CommandClasses.Basic, {
		...V.staticProperty("currentValue", {
			...ValueMetadata.ReadOnlyLevel,
			label: "Current value" as const,
		}),
// ...
});

would result in a type definition like this:

export declare const BasicCCValues: Readonly<{
    currentValue: {
        readonly id: {
            commandClass: CommandClasses.Basic;
            property: "currentValue";
        };
        readonly endpoint: (endpoint?: number | undefined) => {
            readonly commandClass: CommandClasses.Basic;
            readonly endpoint: number;
            readonly property: "currentValue";
        };
        readonly is: (valueId: ValueID) => boolean;
        readonly meta: {
            readonly label: "Current value";
            readonly writeable: false;
            readonly max: 99;
            readonly min: 0;
            readonly type: "number";
            readonly readable: true;
        };
        readonly options: {
            readonly internal: false;
            readonly minVersion: 1;
            readonly secret: false;
            readonly stateful: true;
            readonly supportsEndpoints: true;
            readonly autoCreate: true;
        };
    };
}>;

Since 5.7.2, this is what gets generated. Note that ValueIDBase and TBlueprint are generics type arguments used in the transformation that aren't defined in the output file, so the entire types of the meta and options properties effectively resolve to any. It seems that somewhere along the line, TS just gives up resolving:

export declare const BasicCCValues: Readonly<{
    currentValue: {
        readonly id: ValueIDBase;
        readonly endpoint: (endpoint?: number | undefined) => {
            readonly commandClass: CommandClasses.Basic;
            readonly endpoint: number;
            readonly property: "currentValue";
        };
        readonly is: (valueId: ValueID) => boolean;
        readonly meta: Readonly<(ValueMetadata extends NonNullable<TBlueprint["meta"]> ? Readonly<{
            readonly type: "any";
            readonly readable: true;
            readonly writeable: true;
        }> : import("alcalzone-shared/types").Simplify<import("alcalzone-shared/types").Omit<Readonly<{
            readonly type: "any";
            readonly readable: true;
            readonly writeable: true;
        }>, ("type" | "readable" | "writeable") & keyof NonNullable<TBlueprint["meta"]>> & TBlueprint["meta"]>) extends infer T ? { [K in keyof T as [undefined] extends [(ValueMetadata extends NonNullable<TBlueprint["meta"]> ? Readonly<{
            readonly type: "any";
            readonly readable: true;
            readonly writeable: true;
        }> : import("alcalzone-shared/types").Simplify<import("alcalzone-shared/types").Omit<Readonly<{
            readonly type: "any";
            readonly readable: true;
            readonly writeable: true;
        }>, ("type" | "readable" | "writeable") & keyof NonNullable<TBlueprint["meta"]>> & TBlueprint["meta"]>)[K]] ? never : K]: (ValueMetadata extends NonNullable<TBlueprint["meta"]> ? Readonly<{
            readonly type: "any";
            readonly readable: true;
            readonly writeable: true;
        }> : import("alcalzone-shared/types").Simplify<import("alcalzone-shared/types").Omit<Readonly<{
            readonly type: "any";
            readonly readable: true;
            readonly writeable: true;
        }>, ("type" | "readable" | "writeable") & keyof NonNullable<TBlueprint["meta"]>> & TBlueprint["meta"]>)[K]; } : never>;
        readonly options: Readonly<(import("@zwave-js/cc").CCValueOptions extends NonNullable<TBlueprint["options"]> ? {
            readonly internal: false;
            readonly minVersion: 1;
            readonly secret: false;
            readonly stateful: true;
            readonly supportsEndpoints: true;
            readonly autoCreate: true;
        } : import("alcalzone-shared/types").Simplify<import("alcalzone-shared/types").Omit<{
            readonly internal: false;
            readonly minVersion: 1;
            readonly secret: false;
            readonly stateful: true;
            readonly supportsEndpoints: true;
            readonly autoCreate: true;
        }, ("stateful" | "secret" | "internal" | "minVersion" | "supportsEndpoints" | "autoCreate") & keyof NonNullable<TBlueprint["options"]>> & TBlueprint["options"]>) extends infer T ? { [K in keyof T as [undefined] extends [(import("@zwave-js/cc").CCValueOptions extends NonNullable<TBlueprint["options"]> ? {
            readonly internal: false;
            readonly minVersion: 1;
            readonly secret: false;
            readonly stateful: true;
            readonly supportsEndpoints: true;
            readonly autoCreate: true;
        } : import("alcalzone-shared/types").Simplify<import("alcalzone-shared/types").Omit<{
            readonly internal: false;
            readonly minVersion: 1;
            readonly secret: false;
            readonly stateful: true;
            readonly supportsEndpoints: true;
            readonly autoCreate: true;
        }, ("stateful" | "secret" | "internal" | "minVersion" | "supportsEndpoints" | "autoCreate") & keyof NonNullable<TBlueprint["options"]>> & TBlueprint["options"]>)[K]] ? never : K]: (import("@zwave-js/cc").CCValueOptions extends NonNullable<TBlueprint["options"]> ? {
            readonly internal: false;
            readonly minVersion: 1;
            readonly secret: false;
            readonly stateful: true;
            readonly supportsEndpoints: true;
            readonly autoCreate: true;
        } : import("alcalzone-shared/types").Simplify<import("alcalzone-shared/types").Omit<{
            readonly internal: false;
            readonly minVersion: 1;
            readonly secret: false;
            readonly stateful: true;
            readonly supportsEndpoints: true;
            readonly autoCreate: true;
        }, ("stateful" | "secret" | "internal" | "minVersion" | "supportsEndpoints" | "autoCreate") & keyof NonNullable<TBlueprint["options"]>> & TBlueprint["options"]>)[K]; } : never>;
    };
}>;

⏯ Playground Link

No response

💻 Code

No response

🙁 Actual behavior

see above

🙂 Expected behavior

see above

Additional information about the issue

I found another issue that might be related, but I'm not familiar enough with the details to know:
#60864

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant