#Generic with union not the same as Union of generic

37 messages · Page 1 of 1 (latest)

quiet juncoBOT
#
m.a.t.t.t#0

Preview:```ts
enum Kind {
program = "program",
one = "one",
two = "two",
three = "three",
four = "four",
}

type One = {
kind: Kind.one
foo: string
}

type Two = {
kind: Kind.two
bar: One
baz: Expr
}

type Three = {
kind: Kind.thr
...```

vernal marlin
#

essentially im finding it strange that:

MyUnion = A | B
MyGeneric<MyUnion>
   !==
(MyGeneric<A> | MyGeneric<B>)
gilded path
#

that's the typical behavior

#

you can think of generic types as functions between types
f(a) + f(b) != f(a + b)

#

they're only equivalent when the union is distributed over, using a conditional, for example:

#

!hb dist

quiet juncoBOT
gilded path
#

not sure what exactly you're trying to achieve here?

vernal marlin
#

im trying to find all narrow types in the schemas for the AST nodes, ie. Expr is the union, but im looking for the members of Expr that are specifically mentioned in the schema

#

it sounds like distributivity is what I am hoping for, but perhaps the way I'm using extends has disabled it?

gilded path
#

which extends are you referring to?

vernal marlin
#

im not sure exactly, there are two being used inside the generic but from looking at the output the union is not being distributed

gilded path
#

which generic are you talking about here?

vernal marlin
#

the handbook says it should distribute over each member of the union, then create a new union of the output for each

however when i manually distribute, I get the desired output

#

Collect<>

gilded path
#

your Collect doesn't have any conditionals

vernal marlin
#

not directly so, but in the 2nd parameter it calls into FilterNarrowed and that uses conditionals

gilded path
#

it's only distributed after the Equals, did you maybe expect it to be distributed before?

vernal marlin
#

ah okay, i shifted things around and this looks like the desired output:

quiet juncoBOT
#
m.a.t.t.t#0

Preview:```ts
enum Kind {
program = "program",
one = "one",
two = "two",
three = "three",
four = "four",
}

type One = {
kind: Kind.one
foo: string
}

type Two = {
kind: Kind.two
bar: One
baz: Expr
}

type Three = {
kind: Kind.thr
...```

vernal marlin
#

i still dont understand why though

gilded path
#

fwiw, i'd recommend something like T extends T to explicitly trigger distribution. any doesn't really affect anything here but it's better to make a habit of not using it

#

also, you can use keyof T directly, you don't need to go through keyof Transform<T>

#

like this:

quiet juncoBOT
#
that_guy977#0

Preview:ts ... type Collect<T> = T extends T ? {[K in keyof T]: FilterNarrowed<T[K]>}[keyof T] : never ...

vernal marlin
#

ah brilliant, thank you. T extends T to turn on distribution sounds like a good idea. it looks better now, im just getting a few extra types in NarrowedExpr that I need to weed out

quiet juncoBOT
#
m.a.t.t.t#0

Preview:```ts
enum Kind {
program = "program",
one = "one",
two = "two",
three = "three",
four = "four",
}

type One = {
kind: Kind.one
foo: string
}

type Two = {
kind: Kind.two
bar: One
baz: Expr
}

type Three = {
kind: Kind.thr
...```

gilded path
#

looks like it's inadvertantly mapping over an array

vernal marlin
#

ah i see, its from the array case i need to handle

gilded path
#

you can use extends readonly unknown[] to check for that

vernal marlin
#
type FilterNarrowed<T> = Equals<T, Expr> extends true
        ? never
        : T extends Expr
            ? T
            : T extends Array<infer E>
                ? Collect<E>
                : T extends object
                    ? Collect<T>
                    : never
#

i ended up with using an infer in case so as to traverse the elements as well

gilded path
#

that also works, though make it readonly as well (ReadonlyArray)

#

although, now you wouldn't be able to map a tuple

vernal marlin
#

: T extends readonly (infer E)[] ?

gilded path
#

that would also work yeah

#

readonly arrays are a superset of mutable arrays, so you would have to check for the readonly version to handle both