简体   繁体   English

如何扩展组件以在 React/TS 中添加默认道具

[英]How to extend a component to add default props in React/TS

I want to extend a component with React/TS (in my case is @mui/x-data-grid DataGrid) to fill the classes prop with my own app classes.我想用 React/TS 扩展一个组件(在我的例子中是 @mui/x-data-grid DataGrid),用我自己的应用程序类填充classes属性。

The way I first tought was to create a component, for example CustomDataGrid, like this:我第一次尝试的方法是创建一个组件,例如 CustomDataGrid,如下所示:

import React from 'react';
import {DataGrid} from '@mui/x-data-grid';

const CustomDataGrid = (props) => {
  return <DataGrid {...props} classes={{root: 'my-root-class'}} />;
};

export default CustomDataGrid;

The problem is that I'm using typescript and I want to maintain the type ability to autocomplete in the IDE.问题是我正在使用 typescript 并且我想在 IDE 中保持自动完成的类型能力。

I also tried to define the type of my component as React.FC< Props>, but take a look at the DataGrid code:我还尝试将组件的类型定义为 React.FC<Props>,但请看一下 DataGrid 代码:

declare const DataGrid: React$1.MemoExoticComponent<React$1.ForwardRefExoticComponent<Omit<Partial<DataGridPropsWithDefaultValues> & DataGridPropsWithComplexDefaultValueBeforeProcessing & DataGridPropsWithoutDefaultValue, DataGridForcedPropsKey> & {
    pagination?: true | undefined;
} & React$1.RefAttributes<HTMLDivElement>>>;

I don't know what to fill in the generic arguments to type the props.我不知道在通用 arguments 中填写什么来键入道具。

Does anyone have an idea of how to do this without losing the autocomplete feature?有没有人知道如何在不丢失自动完成功能的情况下做到这一点?

You can do that by using the React.ComponentProps ¹ utility type to get the type of the props of DataGrid , and TypeScript's Omit to remove classes from it:您可以通过使用React.ComponentProps ¹ 实用程序类型来获取DataGrid的道具的类型,并使用 TypeScript 的Omit从中删除classes来做到这一点:

import React from "react";
import {DataGrid} from "@mui/x-data-grid";

const CustomDataGrid = (props: Omit<React.ComponentProps<typeof DataGrid>, "classes">) => {
    return <DataGrid {...props} classes={{root: "my-root-class"}} />;
};

Here's a breakdown of Omit<Parameters<typeof DataGrid>[0], "classes"> :这是Omit<Parameters<typeof DataGrid>[0], "classes">的细分:

  • typeof DataGrid gets the type of DataGrid (this is TypeScript's typeof , not JavaScript's which would just give us "function" ). typeof DataGrid获取DataGrid的类型(这是 TypeScript 的typeof ,而不是 JavaScript 的,它只会给我们"function" )。
  • React.ComponentProps<...> gives us a tuple type with the types of the parameters of the function in order. React.ComponentProps<...>为我们提供了一个元组类型,其中依次包含 function 的参数类型。
  • Omit<..., "classes"> removes the classes type from it, since you're hardcoding that and presumably don't want people to specify it when using CustomDataGrid . Omit<..., "classes">从中删除classes类型,因为您正在对其进行硬编码,并且可能不希望人们在使用CustomDataGrid时指定它。

Playground example 游乐场示例

If that last bullet point isn't accurate and you do want to allow people to specify classes, you can remove the Omit<..., "classes"> part, but be sure in that case to combine any props.classes specified by the caller with your hardcoded ones;如果最后一个要点不准确,并且您确实希望允许人们指定类,则可以删除Omit<..., "classes">部分,但在这种情况下请确保组合任何由指定的props.classes带有硬编码的呼叫者; the code as it is now would override theirs with yours.现在的代码将用您的代码覆盖他们的代码。 For instance, something like:例如,类似:

const myRootClass = "my-root-class";
const CustomDataGrid = (props: React.ComponentProps<typeof DataGrid>) => {
    const classes = props.classes ?? {};
    if (classes.root) {
        classes.root += ` ${myRootClass}`;
    } else {
        classes.root = myRootClass;
    }
    return <DataGrid {...props} classes={classes} />;
};

¹ There's a note in the inline documentation of ComponentProps saying: ¹ ComponentProps的内联文档中有一条注释说:

NOTE: prefer ComponentPropsWithRef , if the ref is forwarded, or ComponentPropsWithoutRef when refs are not supported.注意:如果 ref 被转发,则首选ComponentPropsWithRef ,如果不支持 refs,则首选ComponentPropsWithoutRef

...so you may want the appropriate one of those instead of ComponentProps itself. ...因此您可能需要其中一个合适的而不是ComponentProps本身。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM