0

I am trying to write a groupBy generic function in Typescript. I wanted to limit the groupBy fields to keys of specific type for a given object. I am using the solution proposed here and it's working fine limiting the keys I can use. The problem occurs later:

type KeysMatchingType<T, V> = {[K in keyof T]-?: T[K] extends V ? K : never}[keyof T];
type GroupByAllowedType = string | number | boolean 

function groupBy<T extends object>(arr: T[], prop: KeysMatchingType<T,GroupByAllowedType>): Map<GroupByAllowedType, T[]> {
  
  const map: Map<GroupByAllowedType, T[]> = new Map()
  return arr.reduce((acc, current) => {
    const key = current[prop]
    const val = acc.get(key)
    
    if(val){
      val.push(current)
    } else {
      acc.set(key, [current]) 
    }
    return acc
  }, map)
}

at const val = acc.get(key) Typescript is complaining that:

Type 'T[string]' is not assignable to type 'GroupByAllowedType'

even tho the key used to index T is limited by type declaration for the parameter, e.g. prop is such a key that T[prop] should return either boolean, string or number

I am just wondering is this a limitation of Typescript or am I doing something wrong? I guess I could use casting with as, but generally I try to avoid it.

1
  • Yes, its a limitation. TypeScript has no clue at that point what can and can not be in T. It only knows that T extends object and that KeysMatchingType does return keyof T. It does not know that these keys are limited to some type of T. Commented Oct 11, 2022 at 11:52

1 Answer 1

1

Change the constraint from object to this:

function groupBy<T extends Record<KeysMatchingType<T, GroupByAllowedType>, GroupByAllowedType>>(arr: T[], prop: KeysMatchingType<T, GroupByAllowedType>): Map<GroupByAllowedType, T[]> {

Similarly to this answer from a while ago, you're able to tell TypeScript that you only care about the keys of T that correspond to GroupByAllowedType simply by using a recursive constraint.

Then as you see here, this one change fixes the error :)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.