我有一个由 constsnt 值初始化的二维枚举值数组。我想以这种方式指定此数组的类型,不允许在数组中的任何位置多次放置相同的值。请注意,我不需要使用每个值。
我该怎么做?
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>
,然后它提示整个论点被重复。但我不知道如何防止这种情况发生。
好的,希望对你有帮助;祝你好运!
关于typescript - 不允许数组重复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59032886/