type Check<A, E = never, R extends unknown[] = []> = A extends [infer F, ...infer T]
? Check<T, E | F, [...R, [F] extends [E] ? never : F]>
: R;
function uniqueItems<const T>(items: Check<T> & T): T {
return items;
}
// hack for TS 5.2.x and older:
// function uniqueItems<T extends readonly [] | [V, ...V[]], V extends PropertyKey | boolean | bigint | null | undefined>(items: Check<T> & T): T {
// return items;
// }
Solution by alexandroppolus #35024
type UniqueItems<T, M = never> = T extends [infer F, ...infer R] ? F extends M ? never : [F, ...UniqueItems<R, M | F>] : []
function uniqueItems<const T>(items: T extends UniqueItems<T> ? T : UniqueItems<T>) {
return items
}
Solution by Mantou1233 #34510
type Ensure<T, _P extends unknown[] = []> =
T extends [ infer F, ...infer R ]
? Ensure<R, [ ..._P, F extends _P[number] ? never : F ]>
: _P extends T ? _P : _P
function uniqueItems<const T>(items: Ensure<T>) {
return items
}
Solution by lvjiaxuan #33600
type UniqueItemsTuple<T>
= {[I in keyof T]: I extends `${number}`
? I extends ExtractSmallest<keyof {[J in keyof T & `${number}` as T[J] extends T[I] ? J : never]: J}> ? T[I]
: { error: `Item duplicated at position ${I}` }
: T[I]}
type ExtractSmallest<N extends string> = keyof {[I in N as [keyof {[J in Exclude<N, I> as `${GreaterThan<I, J>}` & `true`]: never}] extends [never] ? I : never]: never}
type GreaterThan<X extends string, Y extends string, Gt extends boolean | undefined = undefined>
= X extends Y ? Gt extends undefined ? false : Gt
: `${X} ${Y}` extends `${infer A}${infer C} ${infer B}${infer D}` ? GreaterThan<C, D, Gt extends true | false ? Gt : A extends B ? Gt : '9876543210' extends `${any}${X}${any}${Y}${any}` ? true : false>
: X extends '' ? false : true
function uniqueItems<const T>(items: T extends UniqueItemsTuple<T> ? T : UniqueItemsTuple<T>) {
return items
}
Solution by teamchong #33165
type GenerateHintTuple<T, _U = never> = T extends [infer First, ...infer Rest]
? [First extends _U ? never : First, ...GenerateHintTuple<Rest, First | _U>]
: []
function uniqueItems<const T>(items: T extends GenerateHintTuple<T> ? T : GenerateHintTuple<T>) {
return items
}
Solution by Sun79 #33118