web-dev-qa-db-fra.com

Impossible d'invoquer un objet qui est éventuellement «non défini» (2722)

J'ai une composante de bouton. Je le transmette simplement juste un onClick Procédez à de nombreux accessoires facultatifs que j'ai définis.

const Button = (props: ButtonProps) => {
    const handleClick: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement> = e => {
        props.onClick(e);
    }
    return (
        <StyledButton onClick={handleClick}>
            {props.children}
        </StyledButton>
    );
};

Alors j'utilise comme ça

<Button onClick={(e) => {
    console.log(e);
}}>Click me!</Button>

Maintenant, comment peut-on mentionner l'erro en question, objet être éventuellement indéfini? Je crois clairement la fonction et cela aussi selon la définition de type. Donc, je passe un objet à cela. Assez simple!

...
 onClick?: React.MouseEventHandler<HTMLElement>
 ...

J'ai ajouté quelques contrôles plus stricts dans ce projet récemment et pertinents sont

"strictFunctionTypes": true,
"strictNullChecks": true

strict:true ÊTRE DÉJÀ présent, cette erreur n'a jamais eu lieu.

Quel est le problème ici?

Mise à jour - Types ajoutés

export interface IBaseButtonProps {
    type?: ButtonType;
    disabled?: boolean;
    size?: ButtonSize;
    block?: boolean;
    loading?: boolean | { delay?: number };
    icon?: string;
    className?: string;
    prefixCls?: string;
    children?: React.ReactNode;
}

export type AnchorButtonProps = {
    href: string,
    target?: string,
    onClick: React.MouseEventHandler<HTMLElement>
} & IBaseButtonProps & Omit<React.AnchorHTMLAttributes<any>, 'type' | 'onClick'>;


export type NativeButtonProps = {
    onClick: React.MouseEventHandler<HTMLElement>,
    htmlType?: ButtonHTMLType
} & IBaseButtonProps & Omit<React.ButtonHTMLAttributes<any>, 'type' | 'onClick'>;

export type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>

Remarques -

La solution possible consiste à déstructurer les accessoires et à ajouter le projet par défaut. Ou utiliser despitres de défaut de réacteur. Mais pas sûr si je devrais exiger cela vraiment avec des documents.

15
HalfWebDev

juste une réponse transparente

if (props.onClick) props.onClick(e);

si vous définissez des accessoires de fonction et que vous voulez qu'il soit facultatif, définissez-le comme étant,

export type ButtonProps = {
  function?: () => void;
};

Explication : Si vous souhaitez utiliser une fonction comme des accessoires, il peut y avoir des instances lorsque vous souhaitez transmettre cette fonction (en tant que accessoires) et il peut y avoir d'autres instances où vous ne voulez pas le transmettre.

par exemple,

Code commun où appeler le <Home/> composant, disons index.ts/index.js

function myfunction(){
  //do something
  alert("hello")
}

return (
  <>
     <Home myfunction={myfunction}/>    //passing prop
     <Home/>                            // not passing
  </>
)

En JS, home.js

export default function Home({myfunction}) {
  const const1 = "Hello World"
  return (
    //do something
    myfunction();      //IMPORTANT line
  )
}

Maintenant, c'est presque équivalent dans TS, Home.TS

Dans TS, nous définissons des types de tout. Donc, dans ce cas, nous devons définir le type de cette fonction myfunction aussi, que nous passons.

Donc, pour cette fonction, nous réalisons que,

  • Il reçoit aucun paramètre, alors () (parenthèse vide) suffit, si des paramètres sont là, nous devons également définir des types pour eux également.
  • Renvoie rien, donc le type de retour void
export type HomeProps = {
  myfunction?: () => void;
};

export default function Home({ myfunction }: HomeProps) {
  const const1 = "Hello World"
  return (
    //do something
    if (myfunction) myfunction();      //IMPORTANT line
  )
}

Astuce: ci-dessus répondre

0
kishore

La meilleure variante consiste à utiliser ?.call(this: unknown, ...args: any[]) ou ?.apply(this: unknown, args: any[]) méthodes

Donc, imaginons que nous avons les prochaines déclarations

type callback = ((x: number, y: number) => number) | null;

let a: callback;
let b: callback;

a = (x, y) => x + y;   // it works with arrow functions
b = function (x, y) {  // and normal functions
  return x + y;
};

function x(cb1: callback, cb2: callback) {
  console.log(cb1?.call(0, 5, 6));     // in this case you
  console.log(cb2?.call(0, 5, 6));     // cant invoke cb1() or cb2()
  console.log(cb1?.apply(0, [5, 6]));  // but you can use call or apply
  console.log(cb2?.apply(0, [5, 6]));  // where first parameter can be any value
}

x(a, b); // 11 11 11 11

class C {
  public f?: callback;
  public setF() {
    this.f = (x, y) => {
      return x + y;
    };
  }
}
const c = new C(); // same with objects
c.setF();
console.log(c?.f?.call(c, 2, 3)); // 5

0