I have recently started using react with typescript and it seems like something odd is happening when I destructure props with optional / default values. For example take this function to generate a random id:
interface GenKeyIdProps {
length?: number;
}
/**
* Generate a random id (mainly for use with rendering lists of components.
* genKeyId convert Math.random to base 36 (numbers letters), and grab the first ${lenght} characters after the decimal.
* @param length (optional) specify how many characters the id should be. default is 5.
* @returns a string with number and letters of specified length.
*/
export const genKeyId = ({ length = 5 }: GenKeyIdProps) => Math.random().toString(36).substr(2, length);
The problem is when I try to call it:
import { genKeyId } from '../../../helpers';
interface TextWrapperProps {
textLines: string[];
}
const TextWrapper = ({ textLines }: TextWrapperProps) => {
return textLines.map(line => (<div key={genKeyId()}>{line}</div>));
};
export default TextWrapper;
if I do not pass at least an empty object to genKeyId I get the following error: Expected 1 arguments, but got 0.ts(2554).
Why do I need to pass an empty object? Is my GenKeyIdProps interface specifying the props need to be part of an object? I am a bit confused about this.
CodePudding user response:
Is my GenKeyIdProps interface specifying the props need to be part of an object?
Yes, you've defined GenKeyIdProps
as an object. All interface
definitions are objects. Your GenKeyIdProps
is roughly equivalent to:
type GenKeyIdProps = {
length?: number;
};
That is, an object with an optional length
property of type number
.
There's no need for genKeyId
to accept an object, though; it's not a component function, it's just a utility function. You could define it to accept length
directly by removing the destructuring:
export const genKeyId = (length = 5) => Math.random().toString(36).substr(2, length);
Alternatively, if you do want it to accept an object but you want it to be able to be called without one, you can default the parameter you're destructuring:
export const genKeyId = ({ length = 5 }: GenKeyIdProps = {}) => Math.random().toString(36).substr(2, length);
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^
Now you can call genKeyId
A) with an object that has a length
; B) with an object that doesn't have a length
; and C) with no argument at all.
It's up to you whether you want getKeyId
to accept a number or an object with a length
property.