reactjs - forwardRef med defaultProps i Typescript
Jeg prøver å bruke defaultProps i forwardRef. Når jeg bruker MessageBox uten forwardRef fungerer det godt med defaultProps. Men når jeg bruker forwardRef med det, oppstår en feil. Hvordan kan jeg løse det?
typescript: 3.4.5 "react": "^16.8.6",
import React, { forwardRef } from "react";
export interface MessageBoxProps {
test: string;
children: any;
}
const defaultProps: Partial<MessageBoxProps> = {
test: "test"
};
const MessageBox = forwardRef<HTMLDivElement, MessageBoxProps>((props, ref) => {
return <p>{props.test}</p>;
});
MessageBox.defaultProps = defaultProps;
export default MessageBox;
export default function App() {
const ref = React.useRef<HTMLDivElement>(null);
return (
<div className="App">
<Test ref={ref} />
</div>
);
}
Type '{ ref: RefObject<HTMLDivElement>; }' is missing the following properties from type 'MessageBoxProps': test, children
https://codesandbox.io/s/forwardref-with-typescript-knhu3?file=/src/App.tsx:83-244
Svar #1
Det korte svaret ser ut til å være: du kan ikke bruke defaultProps med forward ref. Du bør bruke ES2015 standardinitialisatorer som forklart her
Her er funnene mine i @types/react-kilden, kanskje andre kan hjelpe med å forstå dette bedre.
Du kan ikke definere standardpropper på en komponent før du sender den til React.forwardRef, og det er definitivt en intensjon forwardRef argumenttype én github :
interface ForwardRefRenderFunction<T, P = {}> { (props: P, ref: ForwardedRef<T>): ReactElement | null; displayName?: string | undefined; // explicit rejected with `never` required due to // https://github.com/microsoft/TypeScript/issues/36826 /** * defaultProps are not supported on render functions */ defaultProps?: never | undefined; /** * propTypes are not supported on render functions */ propTypes?: never | undefined; }Returtypen til React.forwardRef har et standard prop-felt som antyder at det er ment å bli korrekt typet når det brukes i jsx forwardRef-typen og returtypen på GitHub:
interface ForwardRefExoticComponent<P> extends NamedExoticComponent<P> { defaultProps?: Partial<P> | undefined; propTypes?: WeakValidationMap<P> | undefined; } function forwardRef<T, P = {}>(render: ForwardRefRenderFunction<T, P>): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>;TypeScript-dokumentasjonen angir eksplisitt at de la til støtte for transformasjon av prop-typer på bibliotekssiden for å tillate at React defaultProp får korrekt type. Fra TypeScript 3 nyheter: 'støtte for defaultProps i JSX':
TypeScript 3.0 legger til støtte for en ny typealias i JSX-navnerommet kalt LibraryManagedAttributes. Denne hjelpetypen definerer en transformasjon av komponentens Props-type, før den brukes til å sjekke et JSX-uttrykk som retter seg mot den; og tillater dermed tilpasning som: hvordan konflikter mellom oppgitte props og avledede props håndteres, hvordan avledninger blir kartlagt, hvordan valgfrihet håndteres, og hvordan avledninger fra forskjellige steder bør kombineres.
Imidlertid siden nevner også følgende for funksjonelle komponenter :
For funksjonskomponenter (tidligere kjent som SFC-er) bruk ES2015 standardinitialisatorer:
function Greet({ name = "world" }: Props) { return <div>Hello {name.toUpperCase()}!</div>; }
Men la oss ikke stoppe der. Hva om vi virkelig vil bruke defaultProp? Jeg trenger å vite hvorfor det ikke fungerer.
Søker etter LibraryManagedAttributed i @types/react gir bare ett treff: Kode fra github:
type LibraryManagedAttributes<C, P> = C extends React.MemoExoticComponent<infer T> | React.LazyExoticComponent<infer T> ? T extends React.MemoExoticComponent<infer U> | React.LazyExoticComponent<infer U> ? ReactManagedAttributes<U, P> : ReactManagedAttributes<T, P> : ReactManagedAttributes<C, P>;
Er dette det? Jeg vil ikke late som om jeg forstår denne siste koden fullt ut, men det er ingen omtale av ForwardRefExoticComponent der. Er dette en feil? Kunne det fungere hvis noe ble lagt til i denne typedefinisjonen? Bør jeg åpne en sak?
Gi meg beskjed om hva dere synes!
Svar #2
Prøv :
export interface MessageBoxProps extends React.AllHTMLAttributes<HTMLDivElement>
{
test?: string;
}
Det fungerte for meg. Nå kan du også sette children, href, onClick og andre attributter.
Her er lenken til den forkede sandkassen: https://codesandbox.io/s/forwardref-with-typescript-forked-sn0u3?file=/src/App.tsx
