Home > Back-end >  When calling a callback function with a conditional type, typescript requires passing a parameter wi
When calling a callback function with a conditional type, typescript requires passing a parameter wi

Time:01-31

There is a function that takes a certain set of arguments. In particular, a callback function that takes as an argument an object or an array of objects that depends on another isArray parameter.

I'm trying to make an addiction.

type Option = {
  name: string
  value: string
> }

type FunctionProps<IsArray extends boolean | undefined> = {
  isArray?: IsArray
  callback: IsArray extends false
>     ? (options: Option) => void
>     : (options: option[]) => void
> }

const func = <T extends boolean | undefined = false>({isArray, callback}: FunctionProps<T>) => {
  const options: Option[] = /* */
  const currentOption: Option = /* */

  if (isArray) {
    callback(options)  // Argument of type 'Option[]' is not assignable to parameter of type 'Option & Option[]'.
  else {
    callback(currentOption)  // Argument of type 'Option' is not assignable to parameter of type 'Option & Option[]'.
>   }
> }

When calling func, everything works as it should, but when calling callback inside func, typescript wants to get the intersection of the types Option & Option[] as an argument. I can explicitly specify the type when calling callback(value as Option & Option[]), but this makes it difficult to understand, and it is not clear what eventually happens inside. Is it possible to define the type more clearly inside? P.S. If I declare the function type like this, nothing will change

type FunctionProps = {
  isArray: false
  callback: (options: Option) => void
} | {
  isArray: true
  callback: (options: Option[]) => void
}

CodePudding user response:

Narrowing callback based on isArray would require a discriminated union FunctionProps is not a discriminated union so TS will not be able to follow the relationship between the property types.

IN this case a better option is to make FunctionProps a discriminated union and not use a type parameter:

type FunctionProps = {
    isArray?: false
    callback: (options: Option) => void
} | {
    isArray: true
    callback: (options: Option[]) => void
}

const func =({ isArray, callback }: FunctionProps) => {
    const options: Option[] = null!
    const currentOption: Option = null!;

    if (isArray) {
        callback(options)  
    } else {
        callback(currentOption)  
    }
}

Playground Link

  • Related