2
votes

Interface Infer Prop à partir du composant stylé

J'essaie de déduire l'interface Props mes composants en les exportant autant que possible. Ce n'est pas un problème avec la classe et les composants fonctionnels, mais si j'essaie de déduire l'interface Props d'un styled-component , l'accessoire est typé sur any ce qui n'est pas idéal.

const OtherBox = (props: BoxInferredProps) => (
  {/* TS won't complain that `props` doesn't have a `iAmNotTyped` property which is desired... */}
  <div style={{ backgroundColor: props.iAmNotTyped}}>{props.children}</div>
);

Avec Box étant un styled-component , je ne peux pas en déduire correctement son interface Props. Lorsque je crée un autre composant qui utilise des tentatives d'utilisation du type Props inféré, il apparaît comme n'importe quel:

interface Props {
  bgColor: string;
  children: React.ReactNode;
}

const Box = styled.div<Props>`
  background-color: ${(p) => p.bgColor};
`;

const Button = (props: Props) => (
  <button style={{ backgroundColor: props.bgColor }}>{props.children}</button>
);

type ButtonInferredProps = React.ComponentProps<typeof Button>;

type BoxInferredProps = React.ComponentProps<typeof Box>;

const OtherBox = (props: BoxInferredProps) => (
  <div style={{ backgroundColor: props.bgColor }}>{props.children}</div>
);

const OtherButton = (props: ButtonInferredProps) => (
  <button style={{ backgroundColor: props.bgColor }}>{props.children}</button>
);

export default function App() {
  return (
    <>
      <Box bgColor="red">Hi! I'm a box! </Box>
      <OtherBox bgColor="purple" backgroundColor="red">
        Hi! I'm another box
      </OtherBox>
      <Button bgColor="blue">Hi! I'm a button</Button>
      <OtherButton bgColor="green">Hi! I'm another button</OtherButton>
    </>
  );
}

https://codesandbox.io/s/styled-components-typescript-forked-7cq4q?file=/src/App.tsx


0 commentaires

3 Réponses :


0
votes

Vous pouvez définir un type comme celui-ci:

import {
 StyledComponentInnerComponent,
 StyledComponentInnerOtherProps,
 AnyStyledComponent
} from 'styled-components';

type inferStyledTypes<T extends AnyStyledComponent> = 
  React.ComponentProps<StyledComponentInnerComponent<T>>
  & StyledComponentInnerOtherProps<T>;

// Use the above type to infer the props:
type BoxInferredProps = inferStyledTypes<typeof Box>


0 commentaires

2
votes

Le type de votre composant de style Box s'affiche sous la forme StyledComponent<"div", any, Props, never> . Ainsi , vous pouvez utiliser de tapuscrit infer le mot - clé pour extraire Props de cette définition de type.

import {StyledComponent} from "styled-components";

type StyledComponentProps<T> = T extends StyledComponent<any, any, infer P, any> ? P : never

type BoxInferredProps = StyledComponentProps<typeof Box>;

Vous obtenez maintenant une erreur de typographie, comme prévu, lorsque vous essayez d'affecter backgroundColor sur OtherBox.


3 commentaires

C'est un essai fantastique! Malheureusement, il ne renvoie pas le type des accessoires réels du composant de réaction qui est stylé. En outre, styled-components exporte une grande partie de cela sous le nom StyledComponentInnerOtherProps . Plutôt cool cependant!


@HassanNaqvi Pouvez-vous décrire le problème? Le BoxInferredProps se BoxInferredProps en Props , et les erreurs intellisense et du compilateur fonctionnent comme prévu. Pourquoi cette réponse n'est-elle pas suffisante?


MISE À JOUR - Ah ha! Il y a bien sûr les accessoires qui sont intrinsèques aux éléments HTML - attributs aria, gestionnaires d'événements, etc ... Cette réponse satisfait élégamment ma question initiale, mais la réponse de @ HassanNaqvi est plus robuste.



0
votes

styled-components exporte un assistant Typescript pour cela.

Il s'appelle StyledComponentPropsWithRef :

import React from 'react';
import styled, { StyledComponentPropsWithRef } from 'styled-components';

const RedLink = styled.a`
  color: red;
`;

type Props = StyledComponentPropsWithRef<typeof RedLink>;

const Link = (props: Props) => <RedLink {...props} />;

export default function App() {
  return <Link href="/" role="button" />;
}

Ce code fonctionne ...


0 commentaires