You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript报错:类型缺少'to'属性,如何无需条件渲染解决?

解决TypeScript无法识别条件props的问题

问题原因

TypeScript无法将typeof url == 'string'这个运行时条件,同时关联到动态选择的Tag类型(Link或'a')和展开的props对象。TS会把Tag的类型推断为typeof Link | 'a',要求props必须满足两者的属性交集,但<a>标签不存在to属性,因此抛出Property 'to' is missing in type错误。

无需条件渲染的解决方案

方案1:用as const收窄Tag类型+类型断言

通过as const让TS明确Tag的具体类型,再用satisfies约束props的类型,最后断言props匹配当前Tag的要求:

import { Link, LinkProps } from 'react-router-dom'

// 用as const收窄Tag的类型,让TS知道它是Link或'a'的具体类型
const Tag = (typeof url === 'string' ? Link : 'a') as const;

// 用satisfies约束props符合对应元素的属性规范
const elementProps = typeof url === 'string' 
  ? {
      to: url,
      onClick(event: React.MouseEvent<HTMLAnchorElement>) {
        setActive(true);
        close(url);
        event.preventDefault();
      }
    } satisfies LinkProps
  : {
      onClick() {
        setActive(true);
        onClick();
      }
    } satisfies React.AnchorHTMLAttributes<HTMLAnchorElement>;

return (
  <Tag
    className={u.joinLaden([styles.pill, active && styles.active], ' ')}
    {...elementProps as typeof elementProps}
  >
    {children}
  </Tag>
);

方案2:使用React.createElement创建元素

React.createElement能根据传入的组件/标签类型自动推断props的类型,完美匹配动态Tag的要求:

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

const Tag = typeof url === 'string' ? Link : 'a';
// 抽离公共props,避免重复
const commonProps = {
  className: u.joinLaden([styles.pill, active && styles.active], ' ')
};

const elementProps = typeof url === 'string' 
  ? {
      ...commonProps,
      to: url,
      onClick(event: React.MouseEvent<HTMLAnchorElement>) {
        setActive(true);
        close(url);
        event.preventDefault();
      }
    }
  : {
      ...commonProps,
      onClick() {
        setActive(true);
        onClick();
      }
    };

// React.createElement会自动根据Tag类型校验props
return React.createElement(Tag, elementProps, children);

补充:优雅的条件渲染方案

如果接受轻量条件渲染,可将公共内容抽成子组件,减少重复代码,同时让TS类型推断更清晰:

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

// 抽离公共内容组件
const PillContent = ({ children }: { children: React.ReactNode }) => (
  <>
    {children}
  </>
);

return typeof url === 'string' ? (
  <Link
    className={u.joinLaden([styles.pill, active && styles.active], ' ')}
    to={url}
    onClick={(event) => {
      setActive(true);
      close(url);
      event.preventDefault();
    }}
  >
    <PillContent>{children}</PillContent>
  </Link>
) : (
  <a
    className={u.joinLaden([styles.pill, active && styles.active], ' ')}
    onClick={() => {
      setActive(true);
      onClick();
    }}
  >
    <PillContent>{children}</PillContent>
  </a>
);

内容的提问来源于stack exchange,提问作者Ricardo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 15:07:28