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

[api-extractor] InternalError: Internal Error: Unable to follow symbol for "TWidgetParams" (generic inside satisfies function) #4740

Open
Haroenv opened this issue May 28, 2024 · 1 comment

Comments

@Haroenv
Copy link

Haroenv commented May 28, 2024

I receive an "internal error" when creating the rollup and using a satisfies type for a generic function

Summary

Not completely sure what's going on of course, but when attempting to make functions that follow a contract, I receive an error from AstSymbolTable.js, which I believe is linked to different generics at play here.

// If you encounter this, please report a bug with a repro.  We're interested to know
// how it can occur.
throw new node_core_library_1.InternalError(
  `Unable to follow symbol for "${identifierNode.text}"`
);

Repro steps

This can be reproduced by running yarn && yarn workspace instantsearch.js build:types in algolia/instantsearch@2a36c37 (part of this algolia/instantsearch#6218 PR)

Expected result: builds, valid rollup gets created

Actual result: does not build, if internal error is ignored/commented out, an invalid rollup gets created with a generic in an argument that isn't defined.

Details

I think this may be related to the "hits", "infiniteHits" and "geoSearch" widgets that I'm attempting to make properly generic now. A notable change is that both "levels" of function are now typed with satisfies instead of const x: T = function x to ensure it can be generic.

Also relevant can be to show how the output rollup.d.ts is wrong:

declare const _default_10: <THit extends object = BaseHit>(widgetParams: InfiniteHitsWidgetParams<THit> & InfiniteHitsConnectorParams<THit>) => {
    $$widgetType: "ais.infiniteHits";
    $$type: "ais.infiniteHits";
    init(initOptions: InitOptions): void;
    render(renderOptions: RenderOptions): void;
    getRenderState(renderState: {
        answers?: WidgetRenderState<AnswersRenderState, AnswersConnectorParams> | undefined;
        autocomplete?: WidgetRenderState<AutocompleteRenderState, AutocompleteConnectorParams> | undefined;
        breadcrumb?: {
            [rootAttribute: string]: WidgetRenderState<BreadcrumbRenderState, BreadcrumbConnectorParams>;
        } | undefined;
        clearRefinements?: WidgetRenderState<ClearRefinementsRenderState, ClearRefinementsConnectorParams> | undefined;
        configure?: WidgetRenderState<ConfigureRenderState, ConfigureConnectorParams> | undefined;
        currentRefinements?: WidgetRenderState<CurrentRefinementsRenderState, CurrentRefinementsConnectorParams> | undefined;
        geoSearch?: WidgetRenderState<GeoSearchRenderState<GeoHit<BaseHit>>, GeoSearchConnectorParams<GeoHit<BaseHit>>> | undefined;
        hierarchicalMenu?: {
            [rootAttribute: string]: WidgetRenderState<HierarchicalMenuRenderState, HierarchicalMenuConnectorParams>;
        } | undefined;
        hits?: WidgetRenderState<HitsRenderState<BaseHit>, HitsConnectorParams<BaseHit>> | undefined;
        hitsPerPage?: WidgetRenderState<HitsPerPageRenderState, HitsPerPageConnectorParams> | undefined;
        infiniteHits?: WidgetRenderState<InfiniteHitsRenderState<BaseHit>, InfiniteHitsConnectorParams<BaseHit>> | undefined;
        menu?: {
            [attribute: string]: WidgetRenderState<MenuRenderState, MenuConnectorParams>;
        } | undefined;
        numericMenu?: {
            [attribute: string]: WidgetRenderState<NumericMenuRenderState, NumericMenuConnectorParams>;
        } | undefined;
        pagination?: WidgetRenderState<PaginationRenderState, PaginationConnectorParams> | undefined;
        poweredBy?: WidgetRenderState<PoweredByRenderState, PoweredByConnectorParams> | undefined;
        queryRules?: WidgetRenderState<QueryRulesRenderState, QueryRulesConnectorParams> | undefined;
        range?: {
            [attribute: string]: WidgetRenderState<RangeRenderState, RangeConnectorParams>;
        } | undefined;
        ratingMenu?: {
            [attribute: string]: WidgetRenderState<RatingMenuRenderState, RatingMenuConnectorParams>;
        } | undefined;
        refinementList?: {
            [attribute: string]: WidgetRenderState<RefinementListRenderState, RefinementListConnectorParams>;
        } | undefined;
        relevantSort?: WidgetRenderState<RelevantSortRenderState, RelevantSortConnectorParams> | undefined;
        searchBox?: WidgetRenderState<SearchBoxRenderState, SearchBoxConnectorParams> | undefined;
        sortBy?: WidgetRenderState<SortByRenderState, SortByConnectorParams> | undefined;
        stats?: WidgetRenderState<StatsRenderState, StatsConnectorParams> | undefined;
        toggleRefinement?: {
            [attribute: string]: WidgetRenderState<ToggleRefinementRenderState, ToggleRefinementConnectorParams>;
        } | undefined;
        voiceSearch?: WidgetRenderState<VoiceSearchRenderState, VoiceSearchConnectorParams> | undefined;
        analytics?: WidgetRenderState<Record<string, unknown>, AnalyticsWidgetParams> | undefined;
        places?: WidgetRenderState<Record<string, unknown>, PlacesWidgetParams> | undefined;
    }, renderOptions: InitOptions | RenderOptions): {
        infiniteHits: {
            showPrevious: () => void;
            showMore: () => void;
            isFirstPage: boolean;
            isLastPage: boolean;
            sendEvent: SendEventForHits;
            bindEvent: BindEventForHits;
            currentPageHits: Hit<BaseHit>[];
            hits: Hit<BaseHit>[];
            results?: SearchResults<Hit<BaseHit>> | undefined;
           // NOTE: here is where it goes wrong, TWidgetParams is not readable in this place and it should be resolved to `InfiniteHitsWidgetParams<THit> & InfiniteHitsConnectorParams<THit>`
            widgetParams: InfiniteHitsConnectorParams<BaseHit> & TWidgetParams;
        };
        answers?: WidgetRenderState<AnswersRenderState, AnswersConnectorParams> | undefined;
        autocomplete?: WidgetRenderState<AutocompleteRenderState, AutocompleteConnectorParams> | undefined;
        breadcrumb?: {
            [rootAttribute: string]: WidgetRenderState<BreadcrumbRenderState, BreadcrumbConnectorParams>;
        } | undefined;
        clearRefinements?: WidgetRenderState<ClearRefinementsRenderState, ClearRefinementsConnectorParams> | undefined;
        configure?: WidgetRenderState<ConfigureRenderState, ConfigureConnectorParams> | undefined;
        currentRefinements?: WidgetRenderState<CurrentRefinementsRenderState, CurrentRefinementsConnectorParams> | undefined;
        geoSearch?: WidgetRenderState<GeoSearchRenderState<GeoHit<BaseHit>>, GeoSearchConnectorParams<GeoHit<BaseHit>>> | undefined;
        hierarchicalMenu?: {
            [rootAttribute: string]: WidgetRenderState<HierarchicalMenuRenderState, HierarchicalMenuConnectorParams>;
        } | undefined;
        hits?: WidgetRenderState<HitsRenderState<BaseHit>, HitsConnectorParams<BaseHit>> | undefined;
        hitsPerPage?: WidgetRenderState<HitsPerPageRenderState, HitsPerPageConnectorParams> | undefined;
        menu?: {
            [attribute: string]: WidgetRenderState<MenuRenderState, MenuConnectorParams>;
        } | undefined;
        numericMenu?: {
            [attribute: string]: WidgetRenderState<NumericMenuRenderState, NumericMenuConnectorParams>;
        } | undefined;
        pagination?: WidgetRenderState<PaginationRenderState, PaginationConnectorParams> | undefined;
        poweredBy?: WidgetRenderState<PoweredByRenderState, PoweredByConnectorParams> | undefined;
        queryRules?: WidgetRenderState<QueryRulesRenderState, QueryRulesConnectorParams> | undefined;
        range?: {
            [attribute: string]: WidgetRenderState<RangeRenderState, RangeConnectorParams>;
        } | undefined;
        ratingMenu?: {
            [attribute: string]: WidgetRenderState<RatingMenuRenderState, RatingMenuConnectorParams>;
        } | undefined;
        refinementList?: {
            [attribute: string]: WidgetRenderState<RefinementListRenderState, RefinementListConnectorParams>;
        } | undefined;
        relevantSort?: WidgetRenderState<RelevantSortRenderState, RelevantSortConnectorParams> | undefined;
        searchBox?: WidgetRenderState<SearchBoxRenderState, SearchBoxConnectorParams> | undefined;
        sortBy?: WidgetRenderState<SortByRenderState, SortByConnectorParams> | undefined;
        stats?: WidgetRenderState<StatsRenderState, StatsConnectorParams> | undefined;
        toggleRefinement?: {
            [attribute: string]: WidgetRenderState<ToggleRefinementRenderState, ToggleRefinementConnectorParams>;
        } | undefined;
        voiceSearch?: WidgetRenderState<VoiceSearchRenderState, VoiceSearchConnectorParams> | undefined;
        analytics?: WidgetRenderState<Record<string, unknown>, AnalyticsWidgetParams> | undefined;
        places?: WidgetRenderState<Record<string, unknown>, PlacesWidgetParams> | undefined;
    };
    getWidgetRenderState({ results, helper, parent, state: existingState, instantSearchInstance, }: InitOptions | RenderOptions): {
        hits: Hit<THit>[];
        currentPageHits: Hit<THit>[];
        sendEvent: SendEventForHits;
        bindEvent: BindEventForHits;
        results: SearchResults<any> | undefined;
        showPrevious: () => void;
        showMore: () => void;
        isFirstPage: boolean;
        isLastPage: boolean;
        widgetParams: InfiniteHitsConnectorParams<THit>;
    };
    dispose({ state }: DisposeOptions): SearchParameters;
    getWidgetUiState(uiState: {
        page?: number | undefined;
        query?: string | undefined;
        configure?: PlainSearchParameters | undefined;
        geoSearch?: {
            boundingBox: string;
        } | undefined;
        hierarchicalMenu?: {
            [rootAttribute: string]: string[];
        } | undefined;
        hitsPerPage?: number | undefined;
        menu?: {
            [attribute: string]: string;
        } | undefined;
        numericMenu?: {
            [attribute: string]: string;
        } | undefined;
        range?: {
            [attribute: string]: string;
        } | undefined;
        ratingMenu?: {
            [attribute: string]: number | undefined;
        } | undefined;
        refinementList?: {
            [attribute: string]: string[];
        } | undefined;
        relevantSort?: number | undefined;
        sortBy?: string | undefined;
        toggle?: {
            [attribute: string]: boolean;
        } | undefined;
        places?: {
            query: string;
            position: string;
        } | undefined;
    }, { searchParameters }: {
        searchParameters: SearchParameters;
        helper: AlgoliaSearchHelper;
    }): {
        page?: number | undefined;
        query?: string | undefined;
        configure?: PlainSearchParameters | undefined;
        geoSearch?: {
            boundingBox: string;
        } | undefined;
        hierarchicalMenu?: {
            [rootAttribute: string]: string[];
        } | undefined;
        hitsPerPage?: number | undefined;
        menu?: {
            [attribute: string]: string;
        } | undefined;
        numericMenu?: {
            [attribute: string]: string;
        } | undefined;
        range?: {
            [attribute: string]: string;
        } | undefined;
        ratingMenu?: {
            [attribute: string]: number | undefined;
        } | undefined;
        refinementList?: {
            [attribute: string]: string[];
        } | undefined;
        relevantSort?: number | undefined;
        sortBy?: string | undefined;
        toggle?: {
            [attribute: string]: boolean;
        } | undefined;
        places?: {
            query: string;
            position: string;
        } | undefined;
    };
    getWidgetSearchParameters(searchParameters: SearchParameters, { uiState }: {
        uiState: {
            page?: number | undefined;
            query?: string | undefined;
            configure?: PlainSearchParameters | undefined;
            geoSearch?: {
                boundingBox: string;
            } | undefined;
            hierarchicalMenu?: {
                [rootAttribute: string]: string[];
            } | undefined;
            hitsPerPage?: number | undefined;
            menu?: {
                [attribute: string]: string;
            } | undefined;
            numericMenu?: {
                [attribute: string]: string;
            } | undefined;
            range?: {
                [attribute: string]: string;
            } | undefined;
            ratingMenu?: {
                [attribute: string]: number | undefined;
            } | undefined;
            refinementList?: {
                [attribute: string]: string[];
            } | undefined;
            relevantSort?: number | undefined;
            sortBy?: string | undefined;
            toggle?: {
                [attribute: string]: boolean;
            } | undefined;
            places?: {
                query: string;
                position: string;
            } | undefined;
        };
    }): SearchParameters;
};

(TWidgetParams is not defined here)

output with showDiagnostics: true: output.txt

Standard questions

Please answer these questions to help us investigate your issue more quickly:

Question Answer
@microsoft/api-extractor version? 7.45.1
Operating system? Mac
API Extractor scenario? rollups I believe
Would you consider contributing a PR? if I know what the solution would be, sure
TypeScript compiler version? 5.4.2 (or maybe 5.1.3)
Node.js version (node -v)? 20.10.0
@Haroenv
Copy link
Author

Haroenv commented May 28, 2024

I think I could work around this issue if there was a way to declare a function with a known contract, but that has a generic (unlike before this PR where the type gets resolved and the generic "filled in" with the default value, and you can't pass it at usage)

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

No branches or pull requests

1 participant