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.`
)
}
}