#generic parameter's specific alternative?

8 messages · Page 1 of 1 (latest)

vernal linden
#

Hi, i am trying to abstract my parsers a bit, and was hoping to write generic type/function that would allow to pass parser functions around...

function parseSome(state: ParserState, input: string): AstSome {...}
function parseOther(state: ParserState, input: string): AstOther {...}
function parseElse(state: ParserState, input: string): AstElse {...}
function parseDifferent(state: ParserState, input: string): AstDifferent {...}

// dozens of various "children" nodes around that have various types
type AaaChildren = (AstSome | AstOther | AstElse)[];
type BbbChildren = (AstOther | AstDifferent)[];
// etc.

interface AstAaa { type: 'aaa', children: AaaChildren }
interface AstBbb { type: 'bbb', children: BbbChildren }

// each of specific children can be identified by pre-defined constant keyword in input, e.g. "some", "other", "else", "different"

type ChildrenParsers<T> = { [key: string]: (parserState, someInput) => "one of T's alternatives" };

function parseChildren<T>(input: string, childrenParsers: ChildrenParsers<T>): "one of T's alternatives" {}

// usage attempt
const aaaNode = parseChildren<AaaChildren>(input, {"some": parseSome, "other": parseOther, "else": parseElse});
const bbbNode = parseChildren<BbbChildren>(input, {"other": parseOther, "different": parseDifferent});

Did i approach this in incorrect way? How could i declare that one of specific sub-types of T is to be returned by a child parser?

dire oracle
#

it's not clear to me what you're trying to do. could you explain in more detail and/or provide a more complete example?

#

i moved your code to a playground and started stubbing out some of the missing pieces. maybe you can continue from here:

floral drumBOT
dire oracle
#

one specific point of confusion: the type parameter in ChildrenParsers is unused. what do you want that T to do? should it be used to limit the type of allowed keys or something like that?

#

after staring at it a bit more, here's my best guess:

floral drumBOT
#
mkantor#0

Preview:```ts
...
type ChildrenParsers<T extends readonly string[]> = {
[I in T & number as T[I]]: (
parserState: ParserState,
someInput: string
) => T[I]
}

declare function parseChildren<
T extends readonly string[]

(
input: string,
childrenParsers: ChildrenParsers<T>
): T[number]
...```

dire oracle
#

it's a bit cleaner if you parameterize over a union of strings rather than a tuple of strings (since you don't seem to actually care about the order/indexes here):