Как инкапсулировать метод объединения или сглаживания в связанный список?

#typescript #linked-list #encapsulation

#typescript #связанный список #инкапсуляция

Вопрос:

У меня есть базовая сборка связанного списка в typescript с различаемым объединением.

 type ListType<T> = {
Kind: "Cons",
Head: T,
Tail: List<T>
} | {
 Kind: "Empty"
}

type ListOperations<T> = {
 reduce: <U>(this: List<T>, f: (state: U, x: T) => U, accumulator: U) => U
 map: <U>(this: List<T>, f: (_: T) => U) => List<U>
 reverse: (this: List<T>) => List<T>
 concat: (this: List<T>, l: List<T>) => List<T>
 toArray: (this: List<T>) => T[]
 join: (this: List<List<T>>) => List<T>
}

type List<T> = ListType<T> amp; ListOperations<T>
  

У меня также есть несколько конструкторов как для пустых, так и для минусов:

 export const Cons = <T>(head: T, tail: List<T>): List<T> => ({
 Kind: "Cons",
 Head: head,
 Tail: tail,
 ...ListOperations()
})

export const Empty = <T>(): List<T> => ({
   Kind: "Empty",
   ...ListOperations()
})
  

И, наконец, у меня есть реализация различных методов:

 const ListOperations = <T>(): ListOperations<T> => ({
reduce: function <U>(this: List<T>, f: (state: U, x: T) => U, accumulator: U): U {
    return this.Kind == "Empty" ? accumulator : this.Tail.reduce(f, f(accumulator, this.Head))
},
map: function <U>(this: List<T>, f: (_: T) => U): List<U> {
    return this.reduce((s, x) => Cons(f(x), s), Empty())
},
reverse: function (this: List<T>): List<T> {
    return this.reduce((s, x) => Cons(x, s), Empty())
},
concat: function (this: List<T>, l: List<T>): List<T> {
    return this.reverse().reduce((s, x) => Cons(x, s), l)
},
toArray: function (this: List<T>): T[] {
    return this.reduce<T[]>((s, x) => s.concat([x]), [])
},
join: function (this: List<List<T>>): List<T> {
    return this.reduce((s, x) => s.concat(x), Empty())
}

})
  

Все работает нормально, но я получаю ошибку компиляции при попытке запустить следующее:

 let x = Cons(1, Cons(2, Cons(3, Cons(4, Empty()))))
let y = x.map(x => x   4)

let z = Cons(x, Cons(y, Empty()))
z.join()
  

Контекст типа «this» List<List<number>> не может быть присвоен
методу типа «this» List<List<List<number>>> .

Это связано с join методом (или flatten , как некоторые из вас могут его называть). Когда я пишу соединение вне типа списка, оно работает, поэтому мой вопрос: есть ли способ явно указать компилятору, this какой тип должен быть List<List<T>> ?

Я уже пробовал использовать extends

join: function <T1 extends List<T>>(this: List<T1>): List<T>

Ответ №1:

Это потому, что ваш список является a List<T> , тогда T как сам является a List<T> . Правильный ввод будет:

  join(this: List<T>): T {
  

Чтобы убедиться, что T это сам список, используйте условный тип:

  join(this: T extends List<*> ? List<T> : "Only nested lists can be joined!"): T