【问题标题】:How can I make sure that all the elements in an array are unique?如何确保数组中的所有元素都是唯一的?
【发布时间】:2023-02-21 19:19:06
【问题描述】:

作为作业项目的一部分,我正在使用 Typescript 为学校构建 Linq 框架。关于 Select 方法,我遇到了问题。我向 Select 传递了一个属性数组,但问题是 Typescript 允许数组中有重复值。在 Typescript 或 Javascript 中有没有一种方法可以只包含唯一值的数组?

现在 Select 方法看起来像这样:

在界面中:

 Select: <K extends keyof T>(this: Table<T, U>, ...properties: K[]) => Table<Omit<T, K>, Pick<T, K> & U>

实施:

    Select: function <K extends keyof T>(this: Table<T, U>, ...properties: K[]): Table<Omit<T, K>, Pick<T, K> & U> {
        let selection = this.data.First.map(entry => pickMany(entry, properties))

        let result = this.data.map(
            first => first.map(entry => omitMany(entry, properties))
            ,
            second => merge_list_types(second.zip(selection))
        )

        return Table(result)
    }

现在可以说:

customers.Select("name", "name", "age")

正如预期的那样,上面的代码会给我一个类型错误,因为已经选择了'name'

【问题讨论】:

  • 使用不允许重复的集合类型
  • Java 和 Javascript 是两个不同的东西。请更正您的标签。
  • 我有说 Java 吗?对不起,我的意思是 Javascript 感谢您的更正

标签: arrays typescript


【解决方案1】:

您不能以一般方式确保数组的唯一性(至少不能以受支持的一般方式,您可以使用递归类型别名做一些疯狂的事情,但它们可能会从一个版本切换到另一个版本)。

我们可以创建一个条件类型,以确保最多多个元素的唯一性,并根据需要添加更多元素。

type Omit<T, K extends PropertyKey> = Pick<T, Extract<keyof T, K>>
type IsUnique<T extends any[]> = UK0<T, "Items are not unique", {}>

type Tail<T extends any[]> = ((...a: T) => void) extends (p: any, ...t: infer P) => void ? P : [];
type UK0<T extends any[], TErr, TOk> = T extends [] ? TOk : T[0] extends Tail<T>[number] ? TErr : UK1<Tail<T>, TErr, TOk>
type UK1<T extends any[], TErr, TOk> = T extends [] ? TOk : T[0] extends Tail<T>[number] ? TErr : UK2<Tail<T>, TErr, TOk>
type UK2<T extends any[], TErr, TOk> = T extends [] ? TOk : T[0] extends Tail<T>[number] ? TErr : UK3<Tail<T>, TErr, TOk>
type UK3<T extends any[], TErr, TOk> = T extends [] ? TOk : T[0] extends Tail<T>[number] ? TErr : UK4<Tail<T>, TErr, TOk>
type UK4<T extends any[], TErr, TOk> = T extends [] ? TOk : T[0] extends Tail<T>[number] ? TErr : UK5<Tail<T>, TErr, TOk>
type UK5<T extends any[], TErr, TOk> = T extends [] ? TOk : T[0] extends Tail<T>[number] ? TErr : UK6<Tail<T>, TErr, TOk>
type UK6<T extends any[], TErr, TOk> = T extends [] ? TOk : T[0] extends Tail<T>[number] ? TErr : "Array to big"

class Table<T, U> {
    Select = function <K extends Array<keyof T>>(this: Table<T, U>, ...properties: K & IsUnique<K>): Table<Omit<T, K[number]>, Pick<T, K[number]> & U> {

        return null!;
    }
}

new Table<{ a: 0, b: 0}, {}>().Select("a") //ok
new Table<{ a: 0, b: 0}, {}>().Select("a", "a") // err
new Table<{ a: 0, b: 0}, {}>().Select("a", "b") //ok

更好的方法实际上是使用对象类型,对象本质上不允许键重复。

class Table<T, U> {
    Select = function <K extends Partial<Record<keyof T, true>>>(this: Table<T, U>, properties: K): Table<Omit<T, keyof K>, Pick<T, keyof K> & U> {

        return null!;
    }
}

new Table<{ a: 0, b: 0}, {}>().Select({ a: true }) //ok
new Table<{ a: 0, b: 0}, {}>().Select({ a: true, a: true }) // err
new Table<{ a: 0, b: 0}, {}>().Select({ a: true, b: true }) //ok

【讨论】:

  • 我正在考虑只传递一个对象作为参数,但我认为老师们更喜欢这种语法Select("a", "b")github.com/hogeschool/Software-Engineering-Minor
  • @IAMTHEBEST 作为一名老师,我可以告诉你这是一个很好的问题。通常我们不介意人们提问 :-)
  • 我想在这个例子中回到你身边,我的一位老师在半途中想出了另一个解决方案。通过使用Exclude。我不知道如何实现这个,但它与制作类型为 K 的元素的数组类型和排除所有已选择的值有关。你知道他的意思或如何实现它吗?
  • @IAMTHEBEST 没有办法解决递归类型别名问题。不允许使用递归类型别名(非常有限的场景除外)。您可以通过某种方式欺骗编译器让您这样做,但它是 a) 不推荐 b) 随着递归检查的改进,可能会在未来的版本中中断(他们确实 GH 充满了递归类型别名,这些别名有效但不t 了)。如果你的老师有更好的版本,我很想看到它,但我怀疑它是否适用于任意大的数组。
  • 我会让你知道
猜你喜欢
  • 1970-01-01
  • 2020-07-11
  • 1970-01-01
  • 2013-12-26
  • 2017-02-08
  • 2012-02-08
  • 1970-01-01
  • 2017-11-01
  • 2018-08-19
相关资源
最近更新 更多