Búsqueda de sitios web

javascript - ¿Existe la posibilidad de especificar la longitud del array que viene de las props?


¿Es posible especificar la longitud del arreglo que proviene de props usando el tipo de Typescript?

Tenemos un arreglo de objetos:

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 }
]

Paso este arreglo como props así:

<DownlineProgress data={arrayPassedViaProps} />

Dentro del componente DownlineProgress definí un tipo:

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

Estoy usando este tipo con props

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

Me gustaría que Typescript me informara cuando estoy pasando props y el arreglo no tiene la longitud correcta, debería contener DOS o TRES objetos

¿Cómo puedo modificar mi type para lograr ese comportamiento?

PD. actualmente estoy usando la declaración if para verificar

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

Respuesta #1

Aquí hay una solución pura en TypeScript:

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? ];

En su caso, dado que en el valor de las props está esperando un objeto con una propiedad llamada data de tipo Data, puede definir el tipo de las props de la siguiente manera:

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

Naturalmente, puedes crear un tipo para un único elemento de propiedad si quieres evitar repetir la clave de propiedad data:

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

interface DownlineProgressBarProp {
    data: Data
}

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

Respuesta #2

Puedes especificar la longitud de un arreglo con estos tipos personalizados:

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]>;

Y luego:

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