禁止数组中的重复项

Posted

技术标签:

【中文标题】禁止数组中的重复项【英文标题】:Disallow duplicates in array 【发布时间】:2020-03-20 19:22:06 【问题描述】:

我有由 constsnt 值初始化的枚举值的二维数组。我想以这种方式指定此数组的类型,即不允许在数组中的任何位置多次放置相同的值。请注意,我不需要使用每个值。

我该怎么做?

Example:

const enum Smth 
  a = "a",
  b = "b",
  c = "c",
  d = "d",


type Unique2dArray<T> = T[][] // Want to write this type

const x: Unique2dArray<Smth> = [ // Should be valid
  [Smth.a, Smth.b],
  [Smth.d],
]

const y: Unique2dArray<Smth> = [ // Should NOT be valid (Smth.a is repeated)
  [Smth.a, Smth.b, Smth.a],
  [Smth.d],
]

const z: Unique2dArray<Smth> = [ // Should NOT be valid (Smth.a is repeated)
  [Smth.a, Smth.b],
  [Smth.d, Smth.a],
]

【问题讨论】:

您需要编译时检查还是运行时检查?另外,您已经尝试过什么? @Caramiriel,编译时。我没有好主意如何做到这一点。我可以轻松编写运行时检查,但我不希望它是运行时的,因为一切都明确地写在代码中。 Is there a way to define type for array with unique items in typescript?的可能重复 【参考方案1】:

我给出这个答案是因为它的二维性质有点复杂。这与this question的答案基本相同:

内嵌评论:

// BlankOut2D<T, K, L> takes a nested tuple T, and a pair of indices, and
// replaces the value in the tuple with never.
// So BlankOut2D<[['a','b'],['c','d']],'0','1'> is [['a',never],['c','d']].
type BlankOut2D<T extends ReadonlyArray<ReadonlyArray<any>>, K extends keyof T, L extends PropertyKey> = 
  [P in keyof T]: T[P] extends infer TP ? 
    [Q in keyof TP]: [P, Q] extends [K, L] ? never : TP[Q]
   : never


// AppearsIn2d<T, V, Y, N> takes a nested tuple T and a value V, 
// and returns Y if the value V is assignable to any element of any element of T
// and returns N otherwise
type AppearsIn2D<T, V, Y = unknown, N = never> = unknown extends 
  [P in keyof T]: T[P] extends infer TP ? 
    [Q in keyof TP]: V extends TP[Q] ? unknown : never
  [keyof TP] : never [keyof T] ? Y : N

// Invalid<T> makes an error message in lieu of custom invalid types 
// (see microsoft/typescript#23689)
type Invalid<T> = Error &  __errorMessage: T ;

// UniquifyTwoD<T> takes a 2-d nested tuple T and returns T iff no repeats
// appear, otherwise it replaces offending repeated elements with an Invalid<>
type UniquifyTwoD<T extends ReadonlyArray<ReadonlyArray<any>>> = 
  [P in keyof T]: T[P] extends infer TP ? 
    [Q in keyof TP]: AppearsIn2D<BlankOut2D<T, P, Q>, TP[Q], Invalid<[TP[Q], "is repeated"]>, TP[Q]>
   : never


// helper function
const asUnique2DSmthArray = <
  A extends ([[]] | (ReadonlyArray<ReadonlyArray<Smth>>)) & UniquifyTwoD<A>
>(
  a: A
) => a;

它的工作原理是这样的:

const x = asUnique2DSmthArray([
  [Smth.a, Smth.b],
  [Smth.d],
]); // okay

const y = asUnique2DSmthArray([
  [Smth.a, Smth.b, Smth.a], // error!
  //~~~~~          ~~~~~~ <-- not assignable to Invalid<[Smth.a, "is repeated"]>
  [Smth.d], 
]); 

const z = asUnique2DSmthArray([
  [Smth.a, Smth.b], // error! 
  //~~~~~ <-- Invalid<[Smth.a, "is repeated"]
  [Smth.d, Smth.a], // error!
  //~~~~~, ~~~~~~ <-- Invalid<[Smth.a | Smth.d, "is repeated"]> ?  
]);

除了重复元素跨越数组时的错误不完美之外,这几乎是可行的。问题是可分配性的失败导致编译器将第二个参数的类型从[Smth.d, Smth.a] 扩大到Array&lt;Smth.d | Smth.a&gt;,然后它抱怨整个参数被重复。但我不知道如何防止这种情况发生。

好的,希望对您有所帮助;祝你好运!

Link to code

【讨论】:

以上是关于禁止数组中的重复项的主要内容,如果未能解决你的问题,请参考以下文章

计算对象数组中的重复项

删除数组中的重复项,但添加一个计数属性以查看重复项的数量

查找和替换数组中的重复项

关于如何去除数组中重复项

js如何去除数组中重复项

从 Kotlin 中的数组中删除重复项