ROODAY
ROODAY

Reputation: 832

Typescript: Enforce that generic T has some property if another prop is present

I have a Table component with props like this:

type TableProps<T extends object> = {
  columns: Column<T>[];
  data: T[];
  expandable?: boolean;
};

I'd like to make it so that if the expandable prop is provided/set to true, it enforces that T extends {details: ReactNode} instead of T extends object, as the details node is what I want to render when expanding a row.

Is it possible to use generics in this way?

Upvotes: 1

Views: 893

Answers (1)

Adrien De Peretti
Adrien De Peretti

Reputation: 3662

My suggestion would be to use the ternary conditional typings. You can find more here

And here is how I suggest you to do

type TablePropsCommonProperties<T> = {
    columns: Column<T>[];
    data: T[];
};

type TablePropsDetails<T extends { details: ReactNode }> = {
    expandable: true;
} & TablePropsCommonProperties<T>;

type TablePropsWithoutDetails<T extends object> = {
    expandable: false;
} & TablePropsCommonProperties<T>;

type TableProps<T extends object> = T extends { details: ReactNode } ? TablePropsDetails<T> : TablePropsWithoutDetails<T>;

/* Valid */
const validWithDetails: TableProps<{ details: ReactNode }> = {
    expandable: true,
    columns: ['test'],
    data: [{ details: <></> }]
}

/* Not Valid, expandable can't be true if details is not provided */
const notValidDithDetails: TableProps<{ prop: string }> = {
    expandable: true,
    columns: ['test'],
    data: [{ prop: 'my prop' }]
}

Hope that it will help you 🚀

Upvotes: 3

Related Questions