gpt4 book ai didi

typescript - 定义 1...n 个字符串模板类型的通用交集类型

转载 作者:行者123 更新时间:2023-12-04 11:56:36 25 4
gpt4 key购买 nike

我正在尝试利用字符串模板文字类型的强大功能为用于定义路由的字符串添加类型安全性。

  • 例如,没有参数的路由可以是任何 string .
  • 带有单个参数的路由必须包含 :parameterName在路径字符串中并包含 parameterName作为 params 中的键/值目的。

  • 我可以手动设置这些类型,而且效果很好。但是我想做的是找到一种方法来消除开发人员手动链接交叉点的需要。我想在我的图书馆里处理。
    type DynamicParam<S extends string> = `:${S}`
    type DynamicParamRoute<T extends string> = `${string}/${DynamicParam<T>}/${string}` | `${DynamicParam<T>}/${string}` | `${string}/${DynamicParam<T>}` | `${DynamicParam<T>}`

    type UserParamRoute = DynamicParamRoute<'user'>

    // const bad1: UserParamRoute = 'user' // error as doesn't match ":user"
    const u1: UserParamRoute = ':user'
    const u2: UserParamRoute = 'prefix/:user'
    const u3: UserParamRoute = ':user/suffix'
    const u4: UserParamRoute = 'prefix/:user/suffix'

    type TeamParamRoute = DynamicParamRoute<'team'>

    const t1: TeamParamRoute = ':team'
    const t2: TeamParamRoute = 'prefix/:team'
    const t3: TeamParamRoute = ':team/suffix'
    const t4: TeamParamRoute = 'prefix/:team/suffix'


    // Combining them to get safety on a multi-param route string

    type UserTeamParamRoute = UserParamRoute & TeamParamRoute // ***** I don't want my library consumer to be responsible for this. ******

    // const ut1: UserTeamParamRoute = 'user/team' // Type '"user/team"' is not assignable to type 'UserTeamParamRoute'.ts(2322)
    // const ut1: UserTeamParamRoute = ':user' // Type '":user"' is not assignable to type 'UserTeamParamRoute'.ts(2322)
    // const ut1: UserTeamParamRoute = ':team' // Type '":team"' is not assignable to type 'UserTeamParamRoute'.ts(2322)

    const ut1: UserTeamParamRoute = ':user/:team'
    const ut2: UserTeamParamRoute = 'prefix/:user/:team'
    const ut3: UserTeamParamRoute = ':user/:team/suffix'
    const ut4: UserTeamParamRoute = ':user/middle/params/:team'
    const tu1: UserTeamParamRoute = ':team/:user'
    const tu2: UserTeamParamRoute = 'prefix/:team/:user'
    const tu3: UserTeamParamRoute = ':team/:user/suffix'
    const tu4: UserTeamParamRoute = ':team/middle/params/:user'
    我尝试了一种将 keyof 用于 params 的方法。对象,但它创建了键的联合。路由定义 需要 params 对象,特别是如果有动态参数。因此,使用它的键似乎是一种生成 path 所需类型的完美方法。的路线。
    const params = {
    user: 'someting',
    team: 'someotherthing'
    } as const

    const ps = ['user', 'team'] as const

    type Params = keyof typeof params


    // Doesn't work, no intersection to force requiring all the keys. Just union of everything
    type RouteParams = DynamicParamRoute<Params> // type RouteParams = ":user" | `${string}/:user/${string}` | `:user/${string}` | `${string}/:user` | ":team" | `${string}/:team/${string}` | `:team/${string}` | `${string}/:team`

    const r1: RouteParams = ':user' // means this is valid
    const p1: RouteParams = ':team' // so is this
    // const rp: RouteParams = 'userteam'
    // const rp0: RouteParams = ''
    // const rp01: RouteParams = 'missingall'
    const rp1: RouteParams = ':user/:team'
    const rp2: RouteParams = 'prefix/:user/:team'
    const rp3: RouteParams = ':user/:team/suffix'
    const rp4: RouteParams = ':user/middle/params/:team'
    const pr1: RouteParams = ':team/:user'
    const pr2: RouteParams = 'prefix/:team/:user'
    const pr3: RouteParams = ':team/:user/suffix'
    const pr4: RouteParams = ':team/middle/params/:user'

    在此先感谢您的任何见解!
    更新:jcalz 解决方案展示为 GIF(我希望它不是太压缩)
    [ Functioning Solution Using jcalz approach1

    最佳答案

    可以到 transform unions to intersections在 TypeScript 中通过某种类型的杂耍将有问题的联合放入 contravariant位置。这是我如何重新定义 DynamicParamRoute<T>使工会在T在输出中变成交叉点:

    type DynamicParamRoute<T extends string> = (T extends any ? (x:
    `${string}/${DynamicParam<T>}/${string}` |
    `${DynamicParam<T>}/${string}` |
    `${string}/${DynamicParam<T>}` |
    `${DynamicParam<T>}`
    ) => void : never) extends ((x: infer I) => void) ? I : never;
    我已经用 (T extends any ? (x: OrigDefinition<T>) => void : never) extends ((x: infer I) => void) ? I : never; 包装了您的原始定义.这需要联合 Tdistributes他们让 OrigDefinition<T>分别适用于每个部分,并将它们作为函数参数(逆变)放在 inferring 之前他们的交集。它有点毛茸茸,但最终它会产生你想要的类型:
    type RouteParams = DynamicParamRoute<Params>
    /* (":user" | `${string}/:user/${string}` | `:user/${string}` | `${string}/:user`) &
    (":team" | `${string}/:team/${string}` | `:team/${string}` | `${string}/:team`) */
    这会导致您想要的错误:
    const r1: RouteParams = ':user' // error!
    const p1: RouteParams = ':team' // error!
    我不确定模式模板文字类型的联合交集在实践中的规模如何,但这无论如何都超出了问题的范围。
    Playground link to code

    关于typescript - 定义 1...n 个字符串模板类型的通用交集类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68025792/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com