【问题标题】:Nested recursive Type Hinting in TypeScript?TypeScript中的嵌套递归类型提示?
【发布时间】:2021-12-05 11:50:59
【问题描述】:

我不完全确定我是否正确,所以我会解释一下。

我正在使用 TypeScript 创建 React 应用程序,为了让我的生活更简单,我想将所有路由路径分别存储为常量,我还希望在 VS Code 中拥有像自动完成这样的 TypeScript。所以我有这个结构之王:

type GlobalRoutingT = 'user' | 'listing';

type RoutingVariants = {
  list: string,
  add: string,
  get: string,
  [key: string]: RoutingVariants | string,
};

type RouterT = Record<GlobalRoutingT, RoutingVariants>;

export const Routes: RouterT = {
  user: {
    list: '/user',
    add: '/user/add',
    get: '/user/:id',
    invoices: {
      list: '/user/invoices',
      add: '/user/invoices/add',
      get: '/user/invoices/:id',
    }
  },
  listing: {
    list: '/listing',
    add: '/listing/add',
    get: '/listing/:id',
  },
};

效果很好,我现在可以这样使用它

<Route path={Routes.user.invoices.get} exact >
  <GetInvoice />
</Route>

但是在 VS Code 里面我得到了错误:

类型'string | 上不存在属性'get'路由变体'。类型“字符串”上不存在属性“获取”。

和 Routes.user.invoices.get 部分突出显示。

我做错了什么?

【问题讨论】:

  • 问题是[key: string]: RoutingVariants | string 说RoutingVariants 的any 属性可以有string 作为类型,所以Routes.user.invoices 在技术上可以是一个字符串。我还不确定如何解决这个问题。
  • @Cerbrus 听起来不错,但令人沮丧,我不明白这是 eslint 问题还是我只是不擅长 TypeScript。
  • 你看过我的回答了吗?我认为这与您所描述的最接近。

标签: typescript visual-studio-code types eslint


【解决方案1】:

您想要的似乎不太可能: How to combine known interface properties with a custom index signature?

您不能将索引签名与同一接口/类型上的命名键结合起来。

作为一种解决方法,您可以使用“子”属性,如下所示:

type GlobalRoutingT = 'user' | 'listing';

type RoutingVariants = {
    list: string,
    add: string,
    get: string,
    child?: Record<string, RoutingVariants>
};

type RouterT = Record<GlobalRoutingT, RoutingVariants>;

export const Routes: RouterT = {
    user: {
        list: '/user',
        add: '/user/add',
        get: '/user/:id',
        child: {
            invoices: {
                list: '/user/invoices',
                add: '/user/invoices/add',
                get: '/user/invoices/:id'
            }
        }
    },
    listing: {
        list: '/listing',
        add: '/listing/add',
        get: '/listing/:id'
    }
};

const a = Routes.user.child?.invoices.get;

请注意我必须如何使用 ?. 来访问孩子,因为它在类型定义中是可选的。

您可以将 child 替换为更短的字母、单个字母、$ 或 _...

【讨论】:

  • 抱歉耽搁了,这看起来是最严格的做法。谢谢
【解决方案2】:

你需要强制类型转换,试试这个:

<Route path={(Routes.user.invoices as RoutingVariants).get} exact >
  <GetInvoice />
</Route>

【讨论】:

  • 有效,但如果继续嵌套,这将很快堆叠;'(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-30
  • 2022-10-06
  • 2010-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多