Skip to content

Commit

Permalink
fix(types): avoid inferring UiState type from initialUiState (#5061)
Browse files Browse the repository at this point in the history
* fix(types): make all usages of UiState in InstantSearch generic

This allows someone with custom widgets to still use setUiState etc. without type errors

* fix lint

* fix(types): avoid inferring UiState type from initialUiState

if you pass initialUiState, that should be asserted by the generic UiState, not automatically accepted. Otherwise you get use cases like the "with function form sets indices state" test where setUiState thinks query is required, just because it has the default given

The way this works is by using `NoInfer` from microsoft/TypeScript#14829 (comment) which seems to be quite relied upon

This is a follow-up on #5060
  • Loading branch information
Haroenv committed Jun 9, 2022
1 parent 2b9e76b commit 80ca07e
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 2 deletions.
7 changes: 6 additions & 1 deletion src/lib/InstantSearch.ts
Expand Up @@ -41,6 +41,11 @@ function defaultCreateURL() {
return '#';
}

// this purposely breaks typescript's type inference to ensure it's not used
// as it's used for a default parameter for example
// source: https://github.com/Microsoft/TypeScript/issues/14829#issuecomment-504042546
type NoInfer<T> = [T][T extends any ? 0 : never];

/**
* Global options for an InstantSearch instance.
*/
Expand Down Expand Up @@ -114,7 +119,7 @@ export type InstantSearchOptions<
* for the first search. To unconditionally pass additional parameters to the
* Algolia API, take a look at the `configure` widget.
*/
initialUiState?: TUiState;
initialUiState?: NoInfer<TUiState>;

/**
* Time before a search is considered stalled. The default is 200ms
Expand Down
4 changes: 3 additions & 1 deletion src/lib/__tests__/InstantSearch-test.tsx
Expand Up @@ -2681,7 +2681,9 @@ describe('onStateChange', () => {
describe('initialUiState', () => {
it('warns if UI state contains unmounted widgets in development mode', async () => {
const searchClient = createSearchClient();
const search = new InstantSearch({
const search = new InstantSearch<
UiState & { [indexName: string]: { customWidget?: { query: string } } }
>({
indexName: 'indexName',
searchClient,
initialUiState: {
Expand Down

0 comments on commit 80ca07e

Please sign in to comment.