reactjs - Videregivelse af en React-komponent som argument til en TypeScript-funktion: pålæg en minimal form af komponentens "props"


Jeg har en TypeScript-funktion med signaturen:

function connectRRC<C extends ComponentType<any>>(component: C)

som i øjeblikket accepterer enhver komponent.

Jeg vil kun acceptere komponenter, der har en given egenskab i "props". F.eks. "id: string".

Gør :

function connectRRC<C extends ComponentType<{ id: string }>>(component: C)

virker ikke, se denne forklaring.

ComponentType defineres i React som:

type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;

interface ComponentClass<P = {}, S = ComponentState> extends StaticLifecycle<P, S> {
    new (props: P, context?: any): Component<P, S>;
    propTypes?: WeakValidationMap<P>;
    contextType?: Context<any>;
    contextTypes?: ValidationMap<any>;
    childContextTypes?: ValidationMap<any>;
    defaultProps?: Partial<P>;
    displayName?: string;
}

interface FunctionComponent<P = {}> {
    (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
    propTypes?: WeakValidationMap<P>;
    contextTypes?: ValidationMap<any>;
    defaultProps?: Partial<P>;
    displayName?: string;
}

Tak på forhånd for eventuelle tips!

Opdatering

@sam256 gav et delvist fungerende svar, som jeg fandt acceptabelt. Dog fandt jeg yderligere brugstilfælde, der ikke virker, uden at finde en rimelig forklaring. Dette TS playground-link viser dem.

Dette virker, som forventet:

class GoodComponent2 extends React.Component<{id:string, otherProp:number} & { somethingElse: boolean }> {}
connectRRC(GoodComponent2)

Men følgende virker ikke:

class BadComponent3<P = { somethingElse: boolean }> extends React.Component<{id:string, otherProp:number} & P> {}
connectRRC(BadComponent3)

class BadComponent4<P = {}> extends React.Component<{id:string, otherProp:number} & P> {}
connectRRC(BadComponent4)

Svar #1

Jeg har et delvist svar.

type RequiredProps = {id:string}

function connectRRC<T extends RequiredProps>(component: React.FC<T>){}

const goodComponent = (props:{id:string, otherProp:number}) => <div />
const badComponent = (props:{otherProp:number}) => <div />

connectRRC(goodComponent)
connectRRC(badComponent) //typescript error

Dette fungerer stort set som du ønsker, fordi Typescript nu udleder T og sikrer, at det udvider RequiredProps.

Det eneste problem er, at dette ikke vil generere en fejl for en komponent, der overhovedet ikke får nogen props. Dette genererer ikke en fejl:

const noPropsComponent = (props:{})=><div />
connectRRC(noPropsComponent)

Årsagen er igen kontravarians, i det mindste delvist, selvom jeg ikke helt forstår, hvad kompilatoren gør her.

Hvad der ser ud til at ske er, at TS ikke udleder T som {} og derfor ikke opfylder begrænsningen (kan nogen forklare hvorfor ikke?)

I stedet ser det ud til, at det antager, at T er mindst RequiredProps (begrænsningen), og derefter blot tjekker, om component opfylder React.FC<RequiredProps>, hvilket det gør, fordi RequiredProps er i den kontravariant position.

Jeg er ikke sikker på en god måde at komme forbi dette på, delvist fordi jeg ikke er sikker på, at jeg helt forstår, hvorfor TS opfører sig på denne måde. Specifikt forstår jeg ikke, hvorfor det ikke udleder T som {} og fejler det for ikke at opfylde RequiredProps-begrænsningen.

Forhåbentlig kan en anden på forumet hjælpe...

Legeplads

Relaterede artikler