#974·rematch

`RematchRootState` second argument default of `Record<string, never>` generates useless state type

Author: illia-bobyrCreated Jul 23, 2022Updated Jul 27, 2022

General description

RematchRootState second argument default value of Record<string, never> does not seem to work for me. It was changed in

refactor: remove redundant Record<string, any>

Commit and line link: https://github.com/rematch/rematch/commit/0f3649e3670fc9c61455eaf776e393cd4a36bf7a#diff-4c2458380e50c967c70d7afe819dc7412180f9f817043f27441de3498e4d0479R292

Unless I specify the second argument value explicitly, as in RematchRootState<RootModel, {}>, derived type expects all properties to have type never, instead of the actual types from the first "models" argument.

I was able to extract a simple case, based on my understanding of the codebase:

typescript
interface Model {
  name?: string,
  state: any
}

interface Models {
  [key: string]: Model
}

interface RootModel extends Models {
  prop: {
    state: number,
  }
}

type RootState<
  TModels extends Models,
  TExtraModels extends Models = Record<string, never>
> = ExtractStateFromModel<TModels, TExtraModels>

type ExtractStateFromModel<
  TModels extends Models,
  TExtraModels extends Models
> = {
  [modelKey in keyof TModels]: TModels[modelKey]['state']
} &
  {
    [modelKey in keyof TExtraModels]: TExtraModels[modelKey]['state']
  }

type MyRootState = RootState<RootModel>;

function buildState(): MyRootState {
  return {
    prop: 10,
  };
}

Run the above on TS Playground with 4.7.4

Expected behavior

I would expect buildState() to type check. Instead, I see the following error:

Type '{ prop: number; }' is not assignable to type 'MyRootState'.
  Type '{ prop: number; }' is not assignable to type '{ [x: string]: never; }'.
    Property 'prop' is incompatible with index signature.
      Type 'number' is not assignable to type 'never'.

I've tried with different TSC versions, starting from version 4.1.5 and up to 4.7.4.