#Nested generic cannot be inferred, appears as unknown

32 messages ยท Page 1 of 1 (latest)

heady patioBOT
#
m.a.t.t.t#0

Preview:```ts
type Boo<T = string> = {boo: T}

type R<A, B extends Boo<A>> = B extends Boo<string>
? true
: false

export function foo<A, B extends Boo<A>>(
b: B
): R<A, B> {
return false as any
}

const a: Boo = {boo: "hoo"}
const b: Boo<number> = {boo: 123}

const x = foo(a)
...```

brisk wadi
#

You don't need A. You can extract the type from B

#

The reason is probably that you don't pass anything with A type for it to infer from, so it defaults to unknown.

#

And Boo<string> does extend Boo<unknown>

#

I can see why you might like TS to infer A as string there, but obviously it doesn't. I would suggest eliminating unneeded types where possible, to make the typing "tighter"

#

Your R type can also use just one generic parameter, either A or B extends Boo<unknown>

spark brook
#

ah thank you, i think i've been typescriptting all day and getting horse blinders

brisk wadi
#

Blinkers?

spark brook
#

yikes, thats the one

#

im probably also overthinking this next example too,

heady patioBOT
#
m.a.t.t.t#0

Preview:```ts
type General<T, X> = {general: T; original: X}

type ReturnGeneric<T, X extends string | number> = (
a: X
) => General<T, X>

const rg: ReturnGeneric = function (a) {}```

spark brook
#

im putting X in the ReturnGeneric parameter list so that I can use it in both the args list and again in the return type, hoping that it will be inferred at the call site by what gets passed in as the first arg

but that prevents me from specifying what the concrete type of T should be

brisk wadi
#

Blinders seems allowed too ๐Ÿ™‚

spark brook
#

oh thats probably also because im in australia, maybe blinders is more common here

brisk wadi
#

Well, when you refer to a generic like that, e.g. to type a variable, you'll need to fully specify it's type params

#

I suppose you could give default types though

spark brook
#

ahhh thats probably it

brisk wadi
#

Is X actually a type argument that you want to be able to specify, or just string | number?

heady patioBOT
#
m.a.t.t.t#0

Preview:```ts
type General<T, X> = {general: T; original: X}

type ReturnGeneric<
T,
X extends string | number = string | number

= (a: X) => General<T, X>

const rg: ReturnGeneric<boolean> = function (a) {
return {general: true, original: a}
}

const x = rg("a")```

spark brook
#

i guess im adding it as the 2nd type argument so that I can use it in both the function args list and then again in the return type... afaik thats the only way to get typescript to evaluate the incoming argument at the callsite to infer what the return type will be?

but in that latest example i just posted, I would have thought x would be { general: boolean, original: string } since I am passing a string into rg(), however it comes back with original: string | number

brisk wadi
#

So you want to call rg with a string or number, and it will give back the same type?

spark brook
#

yeah thats the idea, so x.general will be the concrete type passed to ReturnGeneric (in this case boolean)

and x.original will be the same type as the first function parameter

brisk wadi
#

There's no inference on type arguments to generic types. What you want is to have a generic type with a single type argument T, that returns a generic function with 1 type arg X. So you'll have two separate <> blocks in ReturnGeneric

#

The <X...> goes just before the (a: X)

spark brook
#

ohhhh i didnt know you could do that! awesome

#

type ReturnGeneric<T> = <X extends string | number>(a: X) => General<T, X>

brisk wadi
#

Yeah

#

It was something I just realised a few days ago when talking about generic function types with someone

spark brook
#

i feel like the docs could definitely go a lot deeper with generics

brisk wadi
#

I don't read the docs ๐Ÿ˜„

#

I didn't find them so great

#

People here are very good though