30178-hard-unique-items
Hard
tuple
application
cif

チャレンジのソース: type-challenges/30178-hard-unique-items

Some concepts in TypeScript can not be described by types, but can be expressed through type constraints. For example, you can't define a type for positive numbers, but you can check whether a number literal type is positive. One of the patterns for applying such constraints is constrained identity function (CIF). A CIF takes one parameter, infers its type, performs additional checks and returns the parameter unmodified.

// Ensures `n` is a positive number
function positive<const N extends number>(n: `${N}` extends `-${string}` ? never : N) {
  return n
}

const a = positive(1) // Ok
const b = positive(-1) // Error, -1 is not assignable to never

Write a CIF uniqueItems that takes a tuple of literals and ensures that all of them are unique. You are free to use either mutable or readonly tuples.

Bonus task: Helpful error messages instead of not assignable to never. Bonus task: Only repeating tuple elements should be treated as errors, not the entire argument.

Loading...
import type { Equal } from '@type-challenges/utils'

declare const readonlyEqual: <A>() => <T>(value: T) => Equal<Readonly<A>, Readonly<T>>
declare const expect: (value: true) => void

// Should work
expect(readonlyEqual<[1, 2, 3]>()(uniqueItems([1, 2, 3])))
expect(readonlyEqual<['a', 'b', 'c']>()(uniqueItems(['a', 'b', 'c'])))
expect(readonlyEqual<[1, 'a', true]>()(uniqueItems([1, 'a', true])))
expect(readonlyEqual<[undefined, null, 3, false]>()(uniqueItems([undefined, null, 3, false])))

// Should error
// @ts-expect-error
uniqueItems([1, 2, 2, 3, 4, 4, 5, 6])
// @ts-expect-error
uniqueItems([true, true, false, false, 'b', 'b'])
// @ts-expect-error
uniqueItems([1, 1])
// @ts-expect-error
uniqueItems([undefined, undefined])
// @ts-expect-error
uniqueItems([null, undefined, null])
// @ts-expect-error
uniqueItems(['test', undefined, 'test'])

// Bonus: Should give detailed errors
uniqueItems([
  1,
  2,
  // @ts-expect-error
  2,
  3,
  4,
  // @ts-expect-error
  4,
  6,
  7,
])

uniqueItems([
  true,
  // @ts-expect-error
  true,
  false,
  // @ts-expect-error
  false,
  'b',
  // @ts-expect-error
  'b',
])