#extends does not work when I want to check an argument of a function

25 messages · Page 1 of 1 (latest)

sullen sundial
#
type Params = { readonly [N: string]: string }
type Props = Omit<{ readonly [N: string]: unknown }, 'params'>

type Load<Pa extends Params, Pr extends Props> = (context: { params: Pa }) => Pr

type ParamsOfLoad<L> = L extends Load<infer Pa, Props> ? Pa : never
type PropsOfLoad<L> = L extends Load<Params, infer Pr> ? Pr : never


type ResultOfLoadParams = ParamsOfLoad<(c: { params: { id: string } }) => { msg: 'hello' }>
type ResultOfLoadProps = PropsOfLoad<(c: { params: { id: string } }) => { msg: 'hello' }>
//     ^ This is `never` even though `{ id: string }` extends Params

sweet martenBOT
#
twosaturdayscode#0

Preview:```ts
type Params = {readonly [N: string]: string}
type Props = Omit<
{readonly [N: string]: unknown},
"params"

type Load<
Pa extends Params,
Pr extends Props

= (context: {params: Pa}) => Pr

type ParamsOfLoad<L> = L extends Load<infer Pa, Props>
? Pa
: never
...```

lilac scarab
#

When check whether A extends B and B is a fuction

#

The args of B have to extend the args of A, Instead of args A extending args B

#

Normally we are assigning values so, we can pass 'a' as a string. But when we pass a function we need to pass a function that will accept a string itself. The receiving type can be a wider type. The function becomes a receiver so needs args types as wide as the specified type.

sweet martenBOT
#
sandiford#0

Preview:ts type R = ((a: string | number) => null) extends ( a: string ) => null ? true : false // ^?

sullen sundial
#

So what you are saying is that I can't do what I'm doing?

#

why it works when it's the return type?

lilac scarab
#

You can do what you want, but you need to use a small constraint

#

Try never as the Params in the extends check.

#

The return value has normal variance. If the function is called it will return and assign that value, pretty much the same as passing a value immediately

sweet martenBOT
#
sandiford#0

Preview:ts type R = ((a: {a: string}) => null) extends ( a: never ) => null ? true : false // ^?

lilac scarab
#

never is assignable to everything, the opposite of unknown really.

sullen sundial
#

Okay this seems weird to me, it's highly probable that I don't know what never really means then

#

I thank you so much for your time and patience please bear with me

#

Can you explain it to me with sets?

#

If I understand right extends means just this is a subset of this right?

#

so in the case of the functions you wrote:

sullen sundial
# sweet marten

Here you are saying that the function (a: string | number) => null is part of the set of functions that are described as (a: string) => null

#

right?

sullen sundial
lilac scarab
#

Never is an empty set, aka the bottom type, so it's within every other set or assignable to every type

#

!:var*

sweet martenBOT
#
tjjfvi#0
`!t6:variance`:

Here's the example with Dog and Animal, explaining co/contra/in variance:

  • Covariance: () => Dog is assignable to () => Animal, because Dog is assignable to Animal; it "preserves the direction of the assignability"
  • Contravariance: (Animal) => void is assignable to (Dog) => void, because something that expects an Animal can also take a Dog; it "reverses the direction of the assignability"
  • Invariance: (Animal) => Animal is not assignable to (Dog) => Dog, because not all returned Animals are Dogs, and (Dog) => Dog is not assignable to (Animal) => Animal, because something expecting a Dog cannot take any other kind of Animal
sullen sundial
#

Thank you very much