#why ts can't infer generic?

1 messages · Page 1 of 1 (latest)

leaden sluiceBOT
#
andreaelektronvolt#0

Preview:```ts
type Parent<T extends number> = {test: T}

const fn = <K extends Parent<T>, T extends number>(
num: T
): Parent<T> => {
return {test: num}
}

type GrandParent = Parent<5>
let x: Parent<5> = fn(5)
let y = fn<GrandParent, 5>(5) // <-- ok
let z = fn<GrandParent>(5) // <-- NOT ok```

grand stratus
#

Yeah so the answer is unfortunately "tsc just didn't design for it". There are issues open for it to say stuff like fn<Parent<123>, _> where the _ allows it to be inferred.

Technically today you could write stuff like fn<Parent<123>, number>.

In present day this is probably the best you can do:

#
const fn = <K extends Parent<any>>(num: T): Parent<K extends Parent<infer T> ? T : never> => { ... }
#

it's not DRY, yeah

strong glade
#

interesting

#

doesnt look to be working

leaden sluiceBOT
#
andreaelektronvolt#0

Preview:```ts
type Parent<T extends number> = {test: T}

const fn = <K extends Parent<T>, T extends number>(num: T): Parent<T> => {
return {test: num}
}

type GrandParent = Parent<5>;
let x: Parent<5> = fn(5);
let y= fn<GrandParent, 5>(5); // <-- ok
let z= fn<GrandParent>(5); // <-- NOT ok
...```

grand stratus
#

Here:

const fn3 = <T extends number>(num: T): Parent<T> => {
    return {test: num}
}
#

if this is actually the problem you want to solve

#

this is the simplest way

strong glade
#

hmm i wish... unfortunately i also need K as the fn output i want to be of type K which extends Parent

grand stratus
#

Yeah then the more full version needs to be this:

const fn3 = <K extends Parent<any>>(num: K extends Parent<infer T> ? T : never): K => {
    return {test: num} as K
}
#

you need the as K because consider if you had SomethingElse = Parent<13> & { extraProperties: string }

#

you can just add excess properties like that, so really for this function to be sound you need to "seal it"

strong glade
#

y

grand stratus
#
const unsound = fn3<{ test: number, newProp: string }>(123);

console.log(unsound.newProp); // This will be `undefined` at runtime but typed as a string.
strong glade
#

yes i have a bunch of utility types

#

its not to have any runtime effects

#

but i want to enforce some types

#

but basically they're all the same

#

without some utility tagging

grand stratus
#

Just explaining that the as K is definitely unsound if you go looking for it

strong glade
#

yeah i already had that i think in my real code

#

in essence they are all number

grand stratus
#

Yeah the typical way to handle problems like this would be Zod

#

or other similar libraries

strong glade
#

never heard of zod

grand stratus
#

alternatively you could look into branded types to make this more sound

primal dirge
#

I think one reason TS hasn't added this sort of feature is that APIs that require manually specifying type params are often misusing generics.

strong glade
#

this is enforced at runtime though right?

grand stratus
#

yeah, depends on the safety you want. For example there's almost certainly a way you could trivially do let x: u8 = 255;, x = 2 * x without runtime validation

grand stratus
strong glade
#

trying to understand that from docs but not really clear

grand stratus
#

Yeah, well z.number().lte(5) won't really stop you from trying to assign 6 at compile time

#

the best way would be z.number().lte(5).brand("some number")

#

I could explain it myself but it's probably easier to just read the docs

#

it's a concept that shows up outside of Zod

strong glade
#

yeah i understand

#

brand its like my tag

grand stratus
#

yup

strong glade
#

didnt know there was a library

grand stratus
#

there's several actually

strong glade
#

this could come very handy

#

my google skills need some homeworks then

grand stratus
#

you could look at Arktype (seems nice if a bit early on), Typebox (never used myself but it seems to integrate better with JSON Schema), etc. etc.

#

searching "TypeScript runtime validator" won't actually get you the best result but it'd at least show you some of them

strong glade
#

well i wanted more a compiletime validator

#

that's probably what i searched

grand stratus
#

yeah I guess in that case you'd need to know the terminology in use

#

"refinement types" can easily be more powerful than what you're seeing here

#

but it's the jargon for this type of compile time validation

#

unfortunately you're more likely to find papers talking about this than actually useful advice by googling