简体   繁体   English

Typescript 属性在扩展类型上不存在

[英]Typescript property does not exist on extended type

I have a react component which either takes the to (react-router-dom prop) or href prop depending on where I want to redirect the user;我有一个 react 组件,它可以使用to (react-router-dom prop) 或href属性,具体取决于我要重定向用户的位置; whether it's within the app or to an external url.无论是在应用程序内还是外部 url。 Typescript complains about my type with Typescript 抱怨我的类型

Property 'to' does not exist on type 'LinkType'.类型“LinkType”上不存在属性“to”。

Property 'href' does not exist on type 'LinkType'.类型“LinkType”上不存在属性“href”。

This is how I defined my type这就是我定义我的类型的方式

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>
    )}
  );
}

Because LinkType is a union, HrefLink and RouterLink are both assignable to LinkType .因为LinkType是一个联合体, HrefLinkRouterLink都可以分配给LinkType HrefLink does not have "to" on it, and RouterLink does not have "href" on it. HrefLink上没有“to”,RouterLink 上也没有“href”。 Therefore typescript can not guarantee that either of those properties exists on the union.因此 typescript 不能保证这些属性中的任何一个都存在于并集上。 You can use a type guard to do what you're trying to while also satisfying 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 (<> ... </>);
}

Another option would be using a "tagged" union to get around the need of a type guard function.另一种选择是使用“标记”联合来解决对类型保护 function 的需求。 These go by some different names depending on who you're talking to.这些 go 有一些不同的名称,具体取决于您与谁交谈。 Other names you can find these by are "discriminating union" and "disjoint union" to name a couple.您可以找到这些的其他名称是“歧视性工会”和“不相交工会”来命名一对。

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 (<> ... </>); 
}

So then if you inspect the type of LinkType['type'] you'll see 'router' | 'href'因此,如果您检查LinkType['type']您将看到'router' | 'href' 'router' | 'href' , and TypeScript can automatically narrow the type for you if you do an if statement on this type property of LinkType. 'router' | 'href'和 TypeScript 可以自动缩小类型,如果您对 LinkType 的此类型属性执行 if 语句。

You can do it like this:你可以这样做:

type LinkType = RouterLink & HrefLink;

That way you don't have to narrow the union with code这样你就不必用代码缩小联合

Edit 1.编辑 1。
Alex D .亚历克斯·D raised a possible side effect of this approach.提出了这种方法可能产生的副作用。 Basically, you'll not be able to define a LinkType object without fulfilling all the properties ( href , label , to ) This can be tackled by using Partials or simply declaring href and to as optional, eg基本上,如果不满足所有属性( hreflabelto ),您将无法定义 LinkType object ,这可以通过使用 Partials 或简单地将hrefto声明为可选来解决,例如

interface HrefLink extends LinkBase {
  href?: string;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM