Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FunctionField in 3.9.0 TypeScript declaration doesn't allow typed record in render prop #5344

Closed
dejancg opened this issue Oct 2, 2020 · 3 comments
Assignees

Comments

@dejancg
Copy link

dejancg commented Oct 2, 2020

In version 3.9.0, the FunctionField is declared like this:

declare const FunctionField: FC<FunctionFieldProps>;
export interface FunctionFieldProps<RecordType extends Record = Record> extends PublicFieldProps, InjectedFieldProps<RecordType>, TypographyProps {
    render: (record?: RecordType, source?: string) => any;
}
export default FunctionField;

Shouldn't it be defined as a generic component?
Because now you can't do this:

<FunctionField<MyRecordType> render={(record?: MyRecordType) => {...}} />

and as it's not generic TypeScript doesn't allow this:

<FunctionField render={(record?: MyRecordType) => {...}} />

Which effectively means you can't have typed record in render prop.

Defining the FunctionField like this seems like it would work:

import * as React from "react";
import { memo } from "react";
import { Record } from "ra-core";
import Typography, { TypographyProps } from "@material-ui/core/Typography";

import sanitizeRestProps from "./sanitizeRestProps";
import { PublicFieldProps, InjectedFieldProps, fieldPropTypes } from "./types";

/**
 * Field using a render function
 *
 * @example
 * <FunctionField
 *     source="last_name" // used for sorting
 *     label="Name"
 *     render={record => record && `${record.first_name} ${record.last_name}`}
 * />
 */
const FunctionField = <RecordType extends Record = Record>({
  className,
  record,
  source = "",
  render,
  ...rest
}: FunctionFieldProps<RecordType>) =>
  record ? (
    <Typography
      component="span"
      variant="body2"
      className={className}
      {...sanitizeRestProps(rest)}
    >
      {render(record, source)}
    </Typography>
  ) : null;

FunctionField.defaultProps = {
  addLabel: true,
};

FunctionField.propTypes = {
  // @ts-ignore
  ...Typography.propTypes,
  ...fieldPropTypes,
};

export interface FunctionFieldProps<RecordType extends Record = Record>
  extends PublicFieldProps,
    InjectedFieldProps<RecordType>,
    TypographyProps {
  render: (record?: RecordType, source?: string) => any;
}

const typedMemo: <T>(c: T) => T = memo;
export default typedMemo(FunctionField);
@dejancg
Copy link
Author

dejancg commented Oct 2, 2020

In the meanwhile, I was able to work around this by using a HOC to wrap the FunctionField:

import React, { FC } from "react";
import { FunctionFieldProps, Record, FunctionField } from "react-admin";

export const GenericFunctionField = <RecordType extends Record = Record>(
  props: FunctionFieldProps<RecordType>
) => {
  const Component = FunctionField as FC<FunctionFieldProps<RecordType>>;
  return <Component {...props} />;
};

@dejancg
Copy link
Author

dejancg commented Oct 6, 2020

Actually, the HOC I used above didn't work out well. Using the field like this with a View component caued labels for GenericFunctionField not be shown. So I removed the HOC and just settled with any for now.

@fzaninotto
Copy link
Member

Fixed by #5370

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants