React Router 如何从路径字符串中推断强类型参数?
How does React Router infer strongly typed arguments from path string?
(这是一个了解工作原理的问题,而不是“我如何...”的问题)
在使用 React Router 时,我意识到 Vscode 当我在这样的路由中输入强类型参数时,IntelliSense 可以向我推荐强类型参数:
<Route path='/users/:userId?' render={props => <UserManager selectedId={props.}/>} />
当我键入 props.match.params.
时,每当我在 path
字符串中输入 :text
作为强类型参数从字符串内部到参数作为强类型 属性(和一个可选参数,如果在我的例子中有问号):
Vscode/TypeScript/React 路由器如何从用户输入的裸字符串生成强类型参数?
请参阅问题仅供参考。
您将在评论中找到解释:
import React from 'react'
type PathParams<
Path extends string
> =
/**
* Check whether provided argument is valid route string with parameters
*/
(Path extends `:${infer Param}/${infer Rest}`
/**
* If yes, call PathParams recursively with rest part of the string
* and make it union with current param
*/
? Param | PathParams<Rest>
/**
* Otherwise, check if argument is standalone parameter, for instance ":userId"
*/
: (Path extends `:${infer Param}`
/**
* If yes, return it
*/
? Param
/**
* Otherwise check if provided string is allowed route string
* but without /, for instance "user:userId"
*/
: (Path extends `${infer _Prefix}:${infer Rest}`
/**
* If yes, call recursively PathParams with this parameter
*/
? PathParams<`:${Rest}`>
/**
* If provided string is invalid - return never
*/
: never)
)
)
/**
* As you might have noticed, we ended up
* with union of strings. Now we just need to convert this union
* into record. It is the easiest part
*/
type Params = PathParams<":siteId/user/:userId">
/**
* Convert union to record with appropriate keys
*/
type PathArgs<Path extends string> = { [K in PathParams<Path>]: string };
// type Result = {
// siteId: string;
// userId: string;
// }
type Result = PathArgs<"/dashboard/:siteId/user:userId">
现在让我们尝试构建类似的 React 组件:
type Props<Path extends string> = {
path: Path,
params: PathArgs<Path>
}
const Route = <Path extends string>(props: Props<Path>) => {
return null
}
const jsx = <Route path="/dashboard/:siteId/user:userId" params={{ siteId: 'hello', userId: 'world' }} /> // ok
const jsx_ = <Route path="/dashboard/:siteId/user:userId" params={{ siteId: 'hello' }} /> // error, missing userId prop
这个例子应该给你一个线索,它是如何在 React 路由器中完成的。我知道我的例子并没有反映 100% 相同的行为,但我仍然相信它是有帮助的
请记住,我的示例比实际实施要小得多。
您可以找到带有注释的 here 原始实现。他们的实现要大得多,因为可能有很多边缘情况。
(这是一个了解工作原理的问题,而不是“我如何...”的问题)
在使用 React Router 时,我意识到 Vscode 当我在这样的路由中输入强类型参数时,IntelliSense 可以向我推荐强类型参数:
<Route path='/users/:userId?' render={props => <UserManager selectedId={props.}/>} />
当我键入 props.match.params.
时,每当我在 path
字符串中输入 :text
作为强类型参数从字符串内部到参数作为强类型 属性(和一个可选参数,如果在我的例子中有问号):
Vscode/TypeScript/React 路由器如何从用户输入的裸字符串生成强类型参数?
请参阅
您将在评论中找到解释:
import React from 'react'
type PathParams<
Path extends string
> =
/**
* Check whether provided argument is valid route string with parameters
*/
(Path extends `:${infer Param}/${infer Rest}`
/**
* If yes, call PathParams recursively with rest part of the string
* and make it union with current param
*/
? Param | PathParams<Rest>
/**
* Otherwise, check if argument is standalone parameter, for instance ":userId"
*/
: (Path extends `:${infer Param}`
/**
* If yes, return it
*/
? Param
/**
* Otherwise check if provided string is allowed route string
* but without /, for instance "user:userId"
*/
: (Path extends `${infer _Prefix}:${infer Rest}`
/**
* If yes, call recursively PathParams with this parameter
*/
? PathParams<`:${Rest}`>
/**
* If provided string is invalid - return never
*/
: never)
)
)
/**
* As you might have noticed, we ended up
* with union of strings. Now we just need to convert this union
* into record. It is the easiest part
*/
type Params = PathParams<":siteId/user/:userId">
/**
* Convert union to record with appropriate keys
*/
type PathArgs<Path extends string> = { [K in PathParams<Path>]: string };
// type Result = {
// siteId: string;
// userId: string;
// }
type Result = PathArgs<"/dashboard/:siteId/user:userId">
现在让我们尝试构建类似的 React 组件:
type Props<Path extends string> = {
path: Path,
params: PathArgs<Path>
}
const Route = <Path extends string>(props: Props<Path>) => {
return null
}
const jsx = <Route path="/dashboard/:siteId/user:userId" params={{ siteId: 'hello', userId: 'world' }} /> // ok
const jsx_ = <Route path="/dashboard/:siteId/user:userId" params={{ siteId: 'hello' }} /> // error, missing userId prop
这个例子应该给你一个线索,它是如何在 React 路由器中完成的。我知道我的例子并没有反映 100% 相同的行为,但我仍然相信它是有帮助的
请记住,我的示例比实际实施要小得多。
您可以找到带有注释的 here 原始实现。他们的实现要大得多,因为可能有很多边缘情况。