Consider these two functions:
const render = (entity) => {
// function body
}
const render = ({
entity,
isAdmin
}) => {
// function body
}
Now let's say I want to call this function. And if it's accepting a destructured object, I should pass the arguments differently.
render({
name: 'John',
age: 40
})
// or
render({
entity: {
name: 'John',
age: 40
},
isAdmin: true
})
Is there a way for me to know if a function accepts destructured object as its parameter?
Please note that render.length
returns 1 for both of these functions. And arguments
does not help me because it's accessible inside the function, not outside it.
Update.
This is the real scenario.
We have an administration panel (similar to React Admin) that is used by over than 500 projects across many companies. You can imagine that we have thousands of lists to be shown in tabular format.
Now, for each table, developers give us a render
function which is a React component to be used for each row of the table.
This is how they use our <List />
component:
const Customers = () => {
return <List
// other props like title, headers, etc.
row={entity => <>
<td>{entity.name}</td>
</>}
/>
}
We don't want to force them across thousands of lists to write row={({entity, metadata}) => <><td>{entity.name}</td></>}
CodePudding user response:
It's not clear to me why you would need to do this. The parameters to a function don't and can't change once declared, and you should always know what parameters a function accepts before calling it.
However, just for the sake of it, here's an example of a way you could do it. Stringify the function, then use a regex to match the ({ })
in the parameter list.
const render1 = (entity) => {}
const render2 = ({
entity,
isAdmin
}) => {}
const render3 = (arg) => someotherFunc({arg})
function doesDestructure(func){
return /\({. }\) =>/gm.test(func.toString().replaceAll("\n", ""))
}
console.log(doesDestructure(render1))
console.log(doesDestructure(render2))
console.log(doesDestructure(render3))
Or a version that will work for all functions:
const render1 = (entity) => {}
const render2 = ({
entity,
isAdmin
}) => {}
const render3 = (entity) => subscribe(({entity}) => { })
function doesDestructure(func){
return /\({. }\)/gm.test(func.toString().replaceAll("\n", "").split("=>")[0])
}
console.log(doesDestructure(render1))
console.log(doesDestructure(render2))
console.log(doesDestructure(render3))
CodePudding user response:
Your original question was definitely an XY Problem but now that you've cleared it up, I believe the issue is...
You have a shared component (probably React) that accepts a function property used to allow callers to dictate how a part of the result is rendered (ie table rows). That function looks something like this currently (Typescript syntax for clarity)
row: (entity: Entity) => JSX.Element
You want to introduce a new element to the renderer including some meta-data but you want to use an object (as opposed to multiple args) to avoid
- Locked in parameter order
- Locked in number of parameters
row: (obj: MetaData & { entity: Entity }) => JSX.Element
To save the sanity of your developers, I would recommend introducing a new callback prop, allowing them to make the change if and when desired
type EntityMeta = MetaData & { entity: Entity };
interface ListProps {
row?: (entity: Entity) => JSX.Element,
rowWithMeta?: (row: EntityMeta) => JSX.Element,
}
In your List
component, you can then make the decision on which renderer to use
const rowRenderer = useCallback(
(row: EntityMeta) => props.rowWithMeta?.(row) ?? props.row?.(row.entity),
[props.rowWithMeta, props.row]
);
return (
<table>
{rows.map((row, i) => (
<tr key={i}>{rowRenderer(row)}</tr>
))}
</table>
);
Personally, the issues you noted regarding point #2 above would not concern me. I would simply construct whatever meta-data you want and pass that as a second parameter
row: (entity: Entity, meta: MetaData)
You can treat that second parameter however you want, just leave the first as purely the entity
return (
<table>
{rows.map(({ entity, ...meta }, i) => (
<tr key={i}>{props.row(entity, meta)}</tr>
))}
</table>
);