Home > Enterprise >  Is there a possibility to specify length of array that comes from props?
Is there a possibility to specify length of array that comes from props?

Time:10-27

Is it possible to specify the length of the array that comes from props using type from Typescript?

We have an array of objects:

const arrayPassedViaProps = [
  { key: '1', label: 'Label 1', value: 9 },
  { key: '2', label: 'Label 2', value: 3 },
  { key: '3', label: 'Label 3', value: 3 },
  { key: '4', label: 'Label 4', value: 22 },
  { key: '5', label: 'Label 5', value: 1 }
]

I pass this array as props like this:

<DownlineProgress data={arrayPassedViaProps} />

Inside DownlineProgress component I defined a type:

type DownlineProgressBarProps = {
  data: {
    key: string
    label: string
    value: number
  }[]
}

I'm using this type with props

export const DownlineProgress = ({data}: DownlineProgressBarProps) => ... 

I would like to be informed by Typescript when I'm passing props that the array doesn't have the correct length, it should contain TWO or THREE objects

How I can modify my type to achieve such behavior?

PS. currently I'm using if statement to check

if(data.length > 3 || data.length < 2){
  throw(`DownlineProgress need an array of length 2 or 3. You pass ${data.length}`)
}

CodePudding user response:

Here is a pure TypeScript solution:

interface Data {
    key: string;
    label: string;
    value: number;
}

// The following type should have two or three elements of type Data
type ArrayWithTwoOrThreeDataElements = [ Data, Data, Data? ];

In your case since in the props value you are expecting an object with a property named data of type Data, you can define the type of props as follow:

type DownlineProgressBarProps = [
    { data: Data }, 
    { data: Data },
    { data: Data }?
];

Naturally you can create a type for a single prop item if you want to avoid repeating the data property key:

interface Data {
    key: string;
    label: string;
    value: number;
}

interface DownlineProgressBarProp {
    data: Data
}

type DownlineProgressBarProps = [
    DownlineProgressBarProp,
    DownlineProgressBarProp,
    DownlineProgressBarProp?
];

CodePudding user response:

You can specify the length of an array with these custom types:

type TupleOf<T, N extends number> = N extends N ? number extends N ? T[] : _TupleOf<T, N, []> : never;
type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N ? R : _TupleOf<T, N, [T, ...R]>;

And then:

type DownlineProgressBarProps = {
  data: TupleOf<{
    key: string
    label: string
    value: number
  }, 2 | 3>
}

CodePudding user response:

You can create a custom function for the same it would be the correct way.

  const propTypes = {
    data: arrayOfLength.bind(null, 2)
  }

  const arrayOfLength = (expectedLength, props, propName, componentName) => {
    const arrayPropLength = props[propName].length

    if (arrayPropLength !== expectedLength) {
      return new Error(
        `Invalid array length ${arrayPropLength} (expected ${expectedLength}) for prop ${propName} supplied to ${componentName}. Validation failed.`
      )
    }
  }
  • Related