Search code examples
reactjstypescriptreact-nativefrontend

Why doesn´t TypeScript generics auto-complete correctly in this case?


Why doesn´t TypeScript correctly assumes the variable "setSortableFields" type in this case?

More details in the comment part of the following code provided

export type TesteProps<
    SortableFields extends (true|false)
> = (
    {
        pending: boolean,
        sortedFields: object,
        sortableFields: SortableFields
    }
    ) & (
    SortableFields extends true ? {
        setSortedFields: object
    } : {
        setSortedFields?: never
        }

    );

export function Teste<
    SortableFields extends (true|false)
>(
    props: TesteProps<SortableFields>
) {
    if (props.sortableFields) {

        const setSortableFields /* here it auto completes with (Object | undefined) instead of assuming it as an Object since the "sortableFields" param is true */ = props.setSortedFields;
        console.log(setSortableFields);
    }
    return <>{JSON.stringify(props)}</>;
}

Solution

    1. I suppose you should declare generic in little another way to avoid its re-declaration during your type usage. (I don't know is it requirements or only beauty-improvement)
    2. Honestly I can't provide answer to question "why". I also often has such expectations and so problems... but code below is working
    // to avoid type duplication - declare this same part of both scenarios into separate type
    // instead of B extends boolean write B = boolean
    // the same as B extends boolean = boolean
    type SharedType<B = boolean> = {
      pending: boolean;
      sortedFields: object;
      sortableFields: B;
    };
    // also use "=" instead of "extends"
    export type TesteProps<
      SortableFields = boolean,
    > = SortableFields extends true ? SharedType<SortableFields> & {
        setSortedFields: object;
      }
      : SharedType<SortableFields>;
    
    // your type coputes in code and no impact on return type
    // so I remove unusable generic from function's defenition 
    export function Teste(
      props: TesteProps,
    ) {
      if (!props.sortableFields) {
        const setSortableFields /* now typescript Error (only with ".sortableFields = true" in if-block no error) */ =
          props.setSortedFields;
        console.log(setSortableFields);
      }
      return <>{JSON.stringify(props)}</>;
    }