I'm currently developing a library that deals with linked lists. The current implementation is hardcoded to work with a list node type containing a "next" field that points to the next node of the same type. However, I am looking to make it more flexible and agnostic to the specific field names used for links. This means it should work whether the list nodes are connected by "prev" references, "next" references, "previous" references, "pointer" references, or even numerical indices (like when using two-element arrays to simulate cons cells). In this case, the user would pass in a string indicating the name of the list link field.
One approach is to allow the library to accept objects conforming to an interface with an index signature of type any
(e.g.,
interface ListNode { [key: string]: any }
), trusting that the user will provide an object with the specified link key. However, I would prefer to validate that the list nodes being passed to the library actually contain the fields with the specified names. This aligns with the purpose of utilizing TypeScript.
My current attempt goes like this:
function doListStuff(head: { [ptr]: ??? }, ptr: string) { ... }
However, I'm struggling to determine what to replace ???
with. Is there a way to define recursive anonymous types?
I also experimented with the following:
interface ListNode<Ptr extends string> {
[Ptr]: ListNode<Ptr> | null;
}
But this resulted in a series of errors:
[ts] A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type. [ts] Cannot find name 'Ptr'. [ts] A computed property name cannot reference a type parameter from its containing type.
So, my question is: is there a way to define an interface with computed property names, or any other method to achieve what I'm aiming for?