如何确保数组中的所有元素都是唯一的?

时间:2019-05-28 07:22:36

标签: arrays typescript

作为作业项目的一部分,我正在用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'

1 个答案:

答案 0 :(得分:2)

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

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

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
相关问题