-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Recursive types? #13
Comments
Hey, Thanks for the request! it is technically possible to use an interesting trick with const Obj = {
prop: Obj // Error: Block-scoped variable 'Obj' used before its declaration.
}
const Obj2 = {
prop: ()=> Obj2
}
console.log('hey it works', Obj2.prop()) Example: https://stackblitz.com/edit/recursive-type?file=index.ts I was thinking about it, but in my own practice I haven't found a need for it. A potential API: import {Union, of, Self} from 'ts-union';
const List = Union({
Empty: of(null),
Elem: of<number, Self>() // 'number' is a type of values to store
}) Then type Or something like that import {Union, of} from 'ts-union';
const List = Union(a => ({
Empty: of(null),
Elem: of(a, ()=>List) // or a wrapper defer(()=>List)
})) Note that the version above is a generic variant, so it is akin to just classic List. I'm not sure if this complexity is worth it, but feel free to maybe sketch out a syntax + types to brainstorm :) |
here's a use case for example, to model effects like the crude attempt: only replaces one level deep. not sure if possible to recurse within the type?? type Substitute<T, ToReplace, Replacement> =
T extends ToReplace
? Replacement
: T extends Array<infer U>
? Array<Substitute<U, ToReplace, Replacement>>
: { [K in keyof T] : Substitute<T[K], ToReplace, Replacement> }
type List =
| { type: 'nil' }
| { type: 'cons', item: number, rest: Self }
type SubbedList = Substitute<List, Self, List> unfortunately |
I kept plugging away - here's a proof-of-concept with the substitution approach |
@m0nkfish that's awesome! |
@twop const List = Union({
nil: Type<null>(),
cons: Type<{ head: number, tail: Self }>(),
})
type List = typeof List.T
function sum(list: List): number {
return List.match(list, {
nil: () => 0,
cons: ({ head, tail }) => head + sum(tail)
})
} |
Upd: I didn't forget about this feature request. I'm working on a new feature: matching tuple of unions, and I don't want to focus on a new feature until I ship an MVP of matching tuples. @m0nkfish thanks again for the patience and working on PoV for recursive types ! <3 |
I'm submitting a ...
[ ] bug report
[x] feature request
[ ] question about the decisions made in the repository
[ ] question about how to use this project
Summary
I'm wondering if it's possible to support recursive ADTs, for example a classic linked list. My own attempts at a generalised ADT library have failed in this regard since the TS compiler can't handle the recursive type aliases
The text was updated successfully, but these errors were encountered: