Website-Suche

reactjs - Warum ist der Typ SFC<AnchorProps> nicht dem Typ SFC<{}> zuweisbar?


Der folgende Code wirft einen Fehler, wenn er von TypeScript kompiliert wird.

import React, { SFC } from "react"
import { Link } from "react-router-dom"
import { HashLink } from "react-router-hash-link"
import MarkdownToJSX from "markdown-to-jsx"

interface AnchorProps {
  baseUrl: string
  relativeUrl: string
  href: string
}

const Anchor: SFC<AnchorProps> = function(props) {
  /*
  FYI, props.baseUrl and props.relativeUrl is used by code I didn’t include in
  this example to keep things simple.
  */
  if (
    props.href.match(/^http(s)?:\/\//) ||
    props.href.match(/^mailto:/) ||
    props.href.match(/^tel:/)
  ) {
    return (
      <a href={props.href} rel="noopener noreferrer" target="_blank">
        {props.children}
      </a>
    )
  } else if (props.href.match(/^#/)) {
    return (
      <HashLink to={props.href} smooth>
        {props.children}
      </HashLink>
    )
  } else {
    return <Link to={props.href}>{props.children}</Link>
  }
}

const Markdown = function() {
  return (
    <MarkdownToJSX
      options={{
        overrides: {
          a: {
            component: Anchor,
            props: {
              baseUrl: "/privacy-guides",
              relativeUrl: "",
            },
          },
        },
      }}
    >
      # This is [markdown](markdown)
    </MarkdownToJSX>
  )
}

export default Markdown
/Users/sunknudsen/Sites/sunknudsen/sunknudsen-website/src/Test.tsx
TypeScript error in /Users/sunknudsen/Sites/sunknudsen/sunknudsen-website/src/Test.tsx(40,13):
No overload matches this call.
  Overload 1 of 2, '(props: Readonly<MarkdownProps>): Markdown', gave the following error.
    Type 'FunctionComponent<AnchorProps>' is not assignable to type 'string | SFC<{}> | ComponentClass<{}, any>'.
      Type 'FunctionComponent<AnchorProps>' is not assignable to type 'SFC<{}>'.
        Types of parameters 'props' and 'props' are incompatible.
          Type '{ children?: ReactNode; }' is not assignable to type 'PropsWithChildren<AnchorProps>'.
            Type '{ children?: ReactNode; }' is missing the following properties from type 'AnchorProps': baseUrl, relativeUrl, href
  Overload 2 of 2, '(props: MarkdownProps, context?: any): Markdown', gave the following error.
    Type 'FunctionComponent<AnchorProps>' is not assignable to type 'string | SFC<{}> | ComponentClass<{}, any>'.
      Type 'FunctionComponent<AnchorProps>' is not assignable to type 'SFC<{}>'.  TS2769

    38 |         overrides: {
    39 |           a: {
  > 40 |             component: Anchor,
       |             ^
    41 |             props: {
    42 |               baseUrl: "/privacy-guides",
    43 |               relativeUrl: "",

Ich verstehe nicht, warum.

Antwort #1

Dies scheint eine Einschränkung der markdown-to-jsx-Typdefinitionen zu sein.

Konkret ist das MarkdownToJSX.options.overrides vom Typ ComponentOverride, und das ComponentOverride ist von diesem Typ:

export type ComponentOverride = string | React.ComponentClass | React.SFC | {
    component: string | React.ComponentClass | React.SFC;
    props?: any;
};

Dieser Typ erlaubt es Ihnen nicht, einen generischen Parameter an React.SFC zu übergeben, was bedeutet, dass er seinen standardmäßigen generischen Parameter verwendet:

type SFC<P = {}> = FunctionComponent<P>;

Dieser Standard-Generik-Parameter ist ein leeres Objekt {}.

Da Ihr Code versucht, einen AnchorProps-Typ einem leeren Objekttyp zuzuweisen, beschwert sich der Compiler.

Ob dies zur Laufzeit ein Problem sein wird, hängt davon ab, wie das zugrunde liegende JavaScript zur Laufzeit funktioniert. Es könnte in Ordnung sein, so zu casten:

const Markdown = function() {
  return (
    <MarkdownToJSX
      options={{
        overrides: {
          a: {
            component: Anchor,
            props: {
              baseUrl: "/privacy-guides",
              relativeUrl: ""
            }
            // We have tested that this works at runtime,
            // we we know more than the compiler knows.
          } as ComponentOverride
        }
      }}
    >
      # This is [markdown](markdown)
    </MarkdownToJSX>
  );
};

Verwandte Artikel