typescript - 不允许数组重复

标签 typescript enums

我有一个由 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],
]

最佳答案

我给出这个答案是因为它的二维性质有点复杂。这基本上与 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<Smth.d | Smth.a> ,然后它提示整个论点被重复。但我不知道如何防止这种情况发生。

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

Link to code

关于typescript - 不允许数组重复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59032886/

相关文章:

angular - 在 redux/ngrx 应用架构中初始化模型对象的位置

python - 元组实例在枚举类中没有成员(pylint no-member)

C# TypeConverter long 到枚举类型在 ChangeType 上失败

swift - 是否可以为 UIDatePicker.Mode 编写 Swift 扩展

c# - 将一些 bool 属性转换为标志枚举

css - 如何在窗口按 Angular 缩放时更新样式

angular - 检查后表达式发生了变化。先前值 : 'initial' . 当前值: 'visible'

javascript - typescript + 终极版 : exclude redux props in parent component

java - 将 JSON 请求中的字符串映射到请求 POJO 中的 Enum

javascript - 我无法在其他 Node 模块工作时导入其中一个 Node 模块