#recursion #typescript
#рекурсия #машинописный текст
Вопрос:
Я работаю над созданием файла Typescript .ds для reactive-coffee (http://yang.github.io/reactive-coffee/api.html ), и я сталкиваюсь с проблемами, пытаясь определить подпись типа для flatten
функции. Пример:
flatten(rx.array([1, [2, 3], rx.cell(4), rx.array([rx.cell([5, rx.cell(6)])])]))
// -> [1,2,3,4,5,6]
flatten([1, [2, 3], rx.cell(4), rx.array([rx.cell([5, rx.cell(6)])])])
// -> [1,2,3,4,5,6]
Вопрос, с которым я столкнулся, заключается в следующем: какова правильная подпись типа Typescript для xs? Пока я придумал что-то вроде этого:
interface NestableCell<T> extends ObsCellInterface<T | NestableCell<T>> {}
type Flattenable<T> = (
Array<T| NestableCell<T | Flattenable<T>> | Flattenable<T>> |
ObsArrayInterface<T | NestableCell<T | Flattenable<T>> | Flattenable<T>>
)
function flatten<T>(xs:Flattenable<T>) => ObsArrayInterface<T>
ObsCellInterface
и ObsArrayInterface
являются типизированными версиями объектов RC ObsCell
и ObsArray
соответственно.
К сожалению, Typescript не допускает рекурсивных типов, только рекурсивные интерфейсы. И на данный момент я действительно не уверен, как преобразовать этот тип в интерфейс.
Ответ №1:
Кажется, что следующее работает, хотя у меня еще не было времени доказать, что оно удовлетворяет всем возможным случаям:
interface NestableCell<T> extends ObsCell<T | NestableCell<T>> {}
interface FlattenableRX<T> extends ObsArray<
T |
NestableCell<T | FlattenableJS<T> | FlattenableRX<T>> |
FlattenableJS<T> |
FlattenableRX<T>
> {}
interface FlattenableJS<T> extends Array<
T |
NestableCell<T | FlattenableJS<T> | FlattenableRX<T>> |
FlattenableJS<T> |
FlattenableRX<T>
> {}
export type Flattenable<T> = FlattenableRX<T> | FlattenableJS<T>
Использование двух взаимно рекурсивных интерфейсов, по-видимому, позволяет избежать наихудших осложнений, связанных с необходимостью поддерживать как примитивные, так и реактивные массивы.
Как я уже сказал, я пока не могу доказать, что это работает, но это, по крайней мере, кажется правдоподобным.