Skip to content

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

Closed
@AlCalzone

Description

@AlCalzone

🔎 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions