扩展类型上不存在 Typescript 属性

时间:2021-04-16 14:05:42

标签: reactjs typescript

我有一个 react 组件,它根据我想将用户重定向到的位置采用 to(react-router-dom 道具)或 href 道具;无论是在应用程序内还是外部网址。打字稿抱怨我的类型

<块引用>

类型“LinkType”上不存在属性“to”。

<块引用>

类型“LinkType”上不存在属性“href”。

这就是我定义我的类型

import React from 'react';
import { Link } from 'react-router-dom';

interface LinkBase {
  label: string;
  icon?: JSX.Element;
}

interface RouterLink extends LinkBase {
  to: string;
}

interface HrefLink extends LinkBase {
  href: string;
}

type LinkType = RouterLink | HrefLink;

export function NavLink(props: LinkType) {
  const { to, label, icon, href } = props;  // TS complains about those to and href

  return(
    {to ? (
      <Link to={to}>{label}</Link>
    ) : (
      <a href={href}>{label}</a>
    )}
  );
}

2 个答案:

答案 0 :(得分:1)

因为 LinkType 是联合,所以 HrefLinkRouterLink 都可以分配给 LinkTypeHrefLink 上没有“to”,RouterLink 上也没有“href”。因此,打字稿不能保证联合中存在这些属性中的任何一个。你可以使用类型保护来做你想做的事情,同时也满足 TypeScript。

import React from 'react';
import { Link } from 'react-router-dom';

interface LinkBase {
  label: string;
  icon?: JSX.Element;
}

interface RouterLink extends LinkBase {
  to: string;
}

interface HrefLink extends LinkBase {
  href: string;
}

type LinkType = RouterLink | HrefLink;

function isRouterLink(v: unknown): v is RouterLink {
  return v && Object.prototype.hasOwnProperty.call(v, 'to');
}

function isHrefLink(v: unknown): v is HrefLink {
  return v && Object.prototype.hasOwnProperty.call(v, 'href');
}

export function NavLink(props: LinkType) {
  const { label, icon } = props; 

  if (isRouterLink(props)) {
    const { to } = props; // typechecks now
    return (<> ... </>)
  }

  if (isHrefLink(props)) {
    const { href } = props;

    return (<> ... </>);
  }

  return (<> ... </>);
}

另一种选择是使用“标记”联合来绕过类型保护函数的需要。这些有一些不同的名称,具体取决于您与谁交谈。您可以通过其他名称找到这些名称是“歧视性联合”和“不相交联合”来命名一对夫妇。

interface LinkBase {
  label: string;
  icon?: JSX.Element;
}

interface RouterLink extends LinkBase {
  type: 'router';
  to: string;
}

interface HrefLink extends LinkBase {
  type: 'href';
  href: string;
}

type LinkType = RouterLink | HrefLink;

export function NavLink(props: LinkType) {
  const { label, icon } = props; 

  if (props.type === 'router') {
    const { to } = props; // typechecks now
    return (<> ... </>);
  }

  if (props.type === 'href') {
    const { href } = props;

    return (<> ... </>);
  }

 return (<> ... </>); 
}

因此,如果您检查 LinkType['type'] 的类型,您将看到 'router' | 'href',并且如果您对 LinkType 的此类型属性执行 if 语句,TypeScript 可以自动为您缩小类型范围。

答案 1 :(得分:0)

你可以这样做:

type LinkType = RouterLink & HrefLink;

这样你就不必用代码缩小联合

编辑 1.
亚历克斯 D。提出了这种方法可能产生的副作用。 基本上,如果不满足所有属性(hreflabelto),您将无法定义 LinkType 对象 这可以通过使用 Partials 或简单地将 hrefto 声明为可选来解决,例如

interface HrefLink extends LinkBase {
  href?: string;
}