我有一个 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>
)}
);
}
答案 0 :(得分:1)
因为 LinkType
是联合,所以 HrefLink
和 RouterLink
都可以分配给 LinkType
。 HrefLink
上没有“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。提出了这种方法可能产生的副作用。
基本上,如果不满足所有属性(href、label、to),您将无法定义 LinkType 对象
这可以通过使用 Partials 或简单地将 href
和 to
声明为可选来解决,例如
interface HrefLink extends LinkBase {
href?: string;
}