#why is this not assignable?

38 messages · Page 1 of 1 (latest)

muted badger
#
type ComponProps = {
  mode?: 'mode1' | 'mode2'
}

function Compon(props: ComponProps) {
  //
}

export type FunctionOrValue<T, Args extends any[] = any[]> = T | ((...args: Args) => T)

type FieldOption<Compon extends (...args: any[]) => any> = {
  element?: Compon
  props?: FunctionOrValue<Parameters<Compon>[0], [any]>
}

const createField = <Compon extends (...args: any[]) => any>(opt: FieldOption<Compon>) => opt

let field = createField({
  element: Compon,

  /** this will be ok */
  // props: {
  //   mode: 'mode1',
  // },

  /** but this shows error, why? */
  /** add "as const" after "'mode1'" literal
   * will be ok but not ideal */
  props: () => {
    return {
      mode: 'mode1',
    }
  },
  /** What Error says: */
  /**
   * Type '() => { mode: string; }' is not assignable to type 'FunctionOrValue<ComponProps, [any]> | undefined'.
   *   Type '() => { mode: string; }' is not assignable to type '(args_0: any) => ComponProps'.
   *     Call signature return types '{ mode: string; }' and 'ComponProps' are incompatible.
   *       The types of 'mode' are incompatible between these types.
   *         Type 'string' is not assignable to type '"mode1" | "mode2" | undefined'.ts(2322)
   * ground.ts(95, 3): The expected type comes from property 'props' which is declared here on type 'FieldOption<(props: ComponProps) => void>'
   */
})
simple arch
#

does turning:

13  | props?: FunctionOrValue<Parameters<Compon>[0], [any]>

into:

13  | props?: FunctionOrValue<ComponProps>

Solve your problem?

or however you need it, just remove the Parameters

pallid olive
#

the object you're returning is being inferred to { mode: string }, as seen in your error.
use as const on the string or the object to get it to infer narrower.

simple arch
pallid olive
#

it's literally what as const is for

simple arch
#

idk, its whats written in the question

pallid olive
#

oh, i didn't notice it.

#

no clue what's up with that then, as const is a proper fix here

simple arch
#

its the double parameter expansion

#

Parameter is overkill and spreading too much

#

removing it from the FieldOption type fixes it

#
type FieldOption<Compon extends (...args: any[]) => any> = {
  element?: Compon
  props?: FunctionOrValue<Compon, [any]>
}
muted badger
#

to build relation between the element and props

pallid olive
#

Parameters isn't the issue here

simple arch
#

but then it's not generic?

pallid olive
#

what?

simple arch
#

im confused now

pallid olive
#

the error is talking about the return type, not the parameter list

simple arch
#

AH

muted badger
#

can you get the idea? the Scenario

#

when you configure a form field, createField({ element: ... props: ... }), props will automatically be the component's props' type

simple arch
#

yeah, i see now

muted badger
#

and ideally , i dont want developers who use this hav to write 'as const'

pallid olive
#

this isn't really about your implementation, it's about how the returned object is structured

muted badger
pallid olive
#

you say it needs to be { mode?: 'mode1' | 'mode2' }, but the value { mode: 'mode1' } doesn't automatically preserve the type of 'mode1', it's broadened to string
that's how literals in ts work

#

if you had mode: string or mode: SomeObject it'd be fine

muted badger
#

ok, so why no error when i just write props object instead of function

pallid olive
#

because there the object never gets broadened, it's immediately checked against the type

muted badger
pallid olive
#

there's nothing to immediately check against

#

it'd check against the return type of the function, but you didn't specify it, so it infers like a normal object

#

you could explictly write the return type of the function as well

unborn krakenBOT
#
that_guy977#0

Preview:ts ... props: (): ComponProps => { return { mode: "mode1", } }, ...