扩展类型上不存在 Typescript 属性

Laz*_*zyk 8 typescript reactjs

我有一个 React 组件,它要么采用to(react-router-dom prop) 要么采用hrefprop,具体取决于我想将用户重定向到哪里;无论是在应用程序内还是外部 URL。Typescript 抱怨我的类型

类型“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>
    )}
  );
}
Run Code Online (Sandbox Code Playgroud)

Ale*_*x D 2

因为LinkType是一个并集,HrefLink并且RouterLink都可以分配给LinkTypeHrefLink上面没有“to”,RouterLink 上也没有“href”。因此,TypeScript 无法保证联合中存在这些属性中的任何一个。您可以使用类型保护来完成您想要做的事情,同时也满足 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 (<> ... </>);
}
Run Code Online (Sandbox Code Playgroud)

另一种选择是使用“标记”联合来解决类型保护函数的需要。根据与您交谈的对象不同,这些名称有不同的名称。您还可以找到这些的其他名称,例如“歧视联盟”和“不相交联盟”。

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 (<> ... </>); 
}
Run Code Online (Sandbox Code Playgroud)

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