Я создаю среду Linq для школы в Typescript в рамках проекта домашнего задания. У меня проблема с методом 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 — разные вещи. Пожалуйста, исправьте свой тег.
Я сказал Джава? Извините, я имел в виду Javascript, спасибо за исправление
Вы не можете обеспечить уникальность массива в общем виде (по крайней мере, не поддерживаемым общим способом, вы можете делать какие-то сумасшедшие вещи с псевдонимом рекурсивного типа, но они, скорее всего, перейдут от версии к другой).
Мы можем создать условный тип, обеспечивающий уникальность до нескольких элементов, и добавить больше по мере необходимости.
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 и исключением уже выбранных значений. Ты хоть представляешь, что он имеет в виду и как это понять?
@IAMTEBEST Невозможно обойти проблему с псевдонимом рекурсивного типа. Псевдонимы рекурсивного типа (за исключением очень ограниченных сценариев) не допускаются. Вы можете каким-то образом обмануть компилятор, чтобы он позволил вам это сделать, но это а) не рекомендуется б) скорее всего, сломается в будущей версии по мере улучшения проверки рекурсивности (и они действительно GH полны псевдонимов рекурсивных типов, которые работали, но не т больше). Если у вашего учителя есть лучшая версия, мне любопытно ее увидеть, но я сомневаюсь, что она работает для произвольно большого массива.
я дам тебе знать
используйте тип коллекции, который не допускает дублирования