#9989Medium

Count Element Number To Object

With type ``CountElementNumberToObject``, get the number of occurrences of every item from an array and return them in an object. For example: Master advanced TypeScript type manipulation in this medium-level challenge on TypeScriptPro.

In this medium-level challenge, you'll implement CountElementNumberToObject<T> which counts the occurrences of every element in a potentially nested array and returns an object mapping each element to its count.

Challenge Instructions: Count Element Number To Object

Medium

With type CountElementNumberToObject, get the number of occurrences of every item from an array and return them in an object. For example:

type Simple1 = CountElementNumberToObject<[]> // return {}
type Simple2 = CountElementNumberToObject<[1,2,3,4,5]>
// return {
//   1: 1,
//   2: 1,
//   3: 1,
//   4: 1,
//   5: 1
// }
 
type Simple3 = CountElementNumberToObject<[1,2,3,4,5,[1,2,3]]>
// return {
//   1: 2,
//   2: 2,
//   3: 2,
//   4: 1,
//   5: 1
// }

Change the following code to make the test cases pass (no type check errors).

ChallengeSolution
type cases = [
  Expect<
    Equal<
      CountElementNumberToObject<[1, 2, 3, 4, 5]>,
      {
        1: 1
        2: 1
        3: 1
        4: 1
        5: 1
      }
    >
  >,
  Expect<
    Equal<
      CountElementNumberToObject<[1, 2, 3, 4, 5, [1, 2, 3]]>,
      {
        1: 2
        2: 2
        3: 2
        4: 1
        5: 1
      }
    >
  >,
  Expect<
    Equal<
      CountElementNumberToObject<[1, 2, 3, 4, 5, [1, 2, 3, [4, 4, 1, 2]]]>,
      {
        1: 3
        2: 3
        3: 2
        4: 3
        5: 1
      }
    >
  >,
  Expect<Equal<CountElementNumberToObject<[never]>, {}>>,

Pro Challenge

Unlock 102+ medium, hard, and extreme challenges to master advanced TypeScript.

One-time payment. Lifetime access.

Detailed Explanation

type Flatten<T extends any[]> = T extends [infer First, ...infer Rest]
  ? First extends any[]
    ? [...Flatten<First>, ...Flatten<Rest>]
    : [First, ...Flatten<Rest>]
  : []
 
type FilterNever<T extends any[]> = T extends [infer First, ...infer Rest]
  ? [First] extends [never]
    ? FilterNever<Rest>
    : [First, ...FilterNever<Rest>]
  : []
 
type Count<T extends any[], V, Acc extends unknown[] = []> = T extends [infer First, ...infer Rest]
  ? Equal<First, V> extends true
    ? Count<Rest, V, [...Acc, unknown]>
    : Count<Rest, V, Acc>
  : Acc['length']
 
type CountElementNumberToObject<T extends any[], F extends any[] = FilterNever<Flatten<T>>> = {
  [K in F[number] as K & PropertyKey]: Count<F, K>
}

How it works:

This challenge helps you understand deep array flattening, element counting at the type level, and mapped types with key remapping, and how to apply these concepts in real-world scenarios.

This challenge is originally from here.

Share this challenge