【发布时间】:2021-06-18 23:55:58
【问题描述】:
我正在尝试利用字符串模板文字类型的力量来为用于定义路由的字符串添加类型安全性。
- 例如,没有参数的路由可以是任何
string。 - 具有单个参数的路由必须在路径字符串中包含
:parameterName并在params对象中包含parameterName作为键/值。
我可以手动设置这些类型,而且效果很好。但我想做的是找到一种方法来消除开发人员手动链接交叉点的需要。我想在我的图书馆里处理它。
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 对象的方法,但它创建了键的联合。路由定义需要参数对象,特别是如果有动态参数。因此,使用它的键来生成路由的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(我希望它不会太压缩)
[
【问题讨论】:
-
“但我想做的是找到一种方法来消除开发人员手动链接交叉点的需要。我想在我的库中处理它。”这是什么意思?
-
您是说您事先不知道 URL 模式会是什么样子?可能是
foo/bar或foo/:bar/baz或任意序列? -
也许您可以提供一个代码示例,说明您如何设想某人理想地使用/使用您的库,因为我不太了解。
-
嘿,jered,我正在为 React Router 编写一个库,其中包含有关如何插入参数的特定字符串规则。基本上,我想要一种可以从 params 对象中推断出键的类型,并使用该类型来为路径字符串中的每个键要求一个
:${key}的实例,包括一些其他要求,例如使用/进行正确分隔。 jcalz 把它钉在了下面!
标签: typescript