-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ExtractRouteParams): Add
ExtractRouteParams
(#24)
* feat(ExtractRouteParams): Add ExtractRouteParams type * test(ExtractRouteParams): Add ExtractRouteParams type test * feat(ExtractRouteParams): Update ExtractRouteParams type * test(ExtractRouteParams): Update ExtractRouteParams type test * docs(ExtractRouteParams): Add ExtractRouteParams documentation
- Loading branch information
1 parent
8549d48
commit 85dc183
Showing
8 changed files
with
271 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# ExtractRouteParams\<Route, ParamType> | ||
|
||
## 개요 | ||
|
||
이 타입은 다양한 제약 조건과 수정자를 고려하여 경로 패턴에서 파라미터 정의를 추출하도록 설계되었어요. 특정 패턴을 따르는 경로 문자열을 처리하고, 다양한 파라미터 수정자를 수용하여 TypeScript에서 파라미터를 정확하게 정의해요. | ||
|
||
- **? (선택적 파라미터)**: 파라미터가 선택적이며, 존재할 수도 있고 존재하지 않을 수도 있음을 나타내요. | ||
- **\* (0 또는 다수의 반복 파라미터)**: 파라미터가 0회 이상 반복될 수 있음을 나타내요. | ||
- **+ (하나 이상의 반복 파라미터)**: 파라미터가 1회 이상 반복되어야 함을 나타내요. | ||
- **'' (기본 필수 파라미터)**: 파라미터가 필수이며 정확히 한 번 나타나야 함을 나타내요. | ||
|
||
## 문법 | ||
|
||
이 타입의 문법은 다소 길고 복잡해요. 문법에 대해서 더 알고 싶다면 [구현](https://github.com/haejunejung/ts-typekit/blob/main/source/url-parser/ExtractRouteParams.d.ts)을 확인해주세요. | ||
|
||
```ts | ||
export type ExtractRouteParams< | ||
Route extends string, | ||
ParamType = string | number | boolean, | ||
>; | ||
``` | ||
|
||
- **Route**: 경로 패턴 문자열이에요. | ||
- **ParamType**: 파라미터 값의 타입을 나타내요. | ||
|
||
## 예제 | ||
|
||
#### 예제 #1 | ||
|
||
```ts | ||
type T0 = ExtractRouteParams<'/users/:userId/posts/:postId'>; | ||
// Result: { userId: string } & { postId: string } | ||
|
||
type T1 = ExtractRouteParams<'/users/:userId/posts/:postId', number>; | ||
// Result: { userId: number } & { postId: number } | ||
|
||
type T2 = ExtractRouteParams<'/users/:userId(\\d+)', number>; | ||
// Result: { userId: number } | ||
|
||
type T3 = ExtractRouteParams<'/search/:query+'>; | ||
// Result: { query: string } | ||
|
||
type T4 = ExtractRouteParams<'/items/:itemId/:category?'>; | ||
// Result: { itemId: string } & { category?: string } | ||
``` | ||
|
||
#### 예제 #2 | ||
|
||
```ts | ||
function buildLink<Route extends string>( | ||
template: Route, | ||
params: ExtractRouteParams<Route, number> | ||
): string { | ||
return template.replace(/:([a-zA-Z0-9_]+)/g, (_, key) => { | ||
const value = params[key as keyof typeof params]; | ||
|
||
if (value !== undefined && value !== null) { | ||
return value.toString(); | ||
} | ||
|
||
throw new Error(`Missing parameter: ${key}`); | ||
}); | ||
} | ||
|
||
const url = buildLink('/users/:userId/products/:productId', { | ||
userId: 1, | ||
productId: 2, | ||
}); | ||
// Result: '/users/1/products/2' | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# ExtractRouteParams\<Route, ParamType> | ||
|
||
## Overview | ||
|
||
This type is designed to extract parameter definitions from a route pattern, considering various constraints and modifiers. It processes route strings that adhere to specific patterns and accommodates different parameter modifiers to accurately define parameters in TypeScript. | ||
|
||
- **? (Optional Parameter)**: Indicates that the parameter is optional and may or may not be present. | ||
- **\* (Zero or More Repeating Paramters)**: Indicates that the parameter can appear zero or more times. | ||
- **+ (One or More Repeating Parameters)**: Indicates that the parameter must appear one or more times. | ||
- **'' (Default Required Parameter)**: Indicates that the paramter is required and must appear exactly once. | ||
|
||
## Syntax | ||
|
||
This type of syntax is rather long and complex. If you want to know more, please check [Implementation](https://github.com/haejunejung/ts-typekit/blob/main/source/url-parser/ExtractRouteParams.d.ts) | ||
|
||
```ts | ||
export type ExtractRouteParams< | ||
Route extends string, | ||
ParamType = string | number | boolean, | ||
>; | ||
``` | ||
|
||
- **Route**: The route pattern string. | ||
- **ParamType**: The type of the parameter values. | ||
|
||
## Examples | ||
|
||
#### Example #1 | ||
|
||
```ts | ||
type T0 = ExtractRouteParams<'/users/:userId/posts/:postId'>; | ||
// Result: { userId: string } & { postId: string } | ||
|
||
type T1 = ExtractRouteParams<'/users/:userId/posts/:postId', number>; | ||
// Result: { userId: number } & { postId: number } | ||
|
||
type T2 = ExtractRouteParams<'/users/:userId(\\d+)', number>; | ||
// Result: { userId: number } | ||
|
||
type T3 = ExtractRouteParams<'/search/:query+'>; | ||
// Result: { query: string } | ||
|
||
type T4 = ExtractRouteParams<'/items/:itemId/:category?'>; | ||
// Result: { itemId: string } & { category?: string } | ||
``` | ||
|
||
#### Example #2 | ||
|
||
```ts | ||
function buildLink<Route extends string>( | ||
template: Route, | ||
params: ExtractRouteParams<Route, number> | ||
): string { | ||
return template.replace(/:([a-zA-Z0-9_]+)/g, (_, key) => { | ||
const value = params[key as keyof typeof params]; | ||
|
||
if (value !== undefined && value !== null) { | ||
return value.toString(); | ||
} | ||
|
||
throw new Error(`Missing parameter: ${key}`); | ||
}); | ||
} | ||
|
||
const url = buildLink('/users/:userId/products/:productId', { | ||
userId: 1, | ||
productId: 2, | ||
}); | ||
// Result: '/users/1/products/2' | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './basic'; | ||
export * from './string'; | ||
export * from './special'; | ||
export * from './url-parser'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/** | ||
* @description | ||
* Defines the different types of parameter modifiers used in URL route patterns. | ||
* These modifiers determine the nature and constraints of parameters within the route. | ||
* | ||
* - `?` (Optional Parameter): Indicates that the parameter is optional and may or may not be present. | ||
* - `*` (Zero or More Repeating Paramters): Indicates that the parameter can appear zero or more times. | ||
* - `+` (One or More Repeating Parameters): Indicates that the parameter must appear one or more times. | ||
* - `''` (Default Required Parameter): Indicates that the paramter is required and must appear exactly once. | ||
*/ | ||
type ParameterModifier = '?' | '*' | '+' | ''; | ||
|
||
/** | ||
* @description | ||
* Extracts route optional parameters from a given Route pattern. | ||
* | ||
* @template {string} Route - The route pattern string. | ||
* @template {string | number | boolean} ParamType - The type of the parameter values. | ||
*/ | ||
|
||
type ExtractRouteOptionalParam< | ||
Route extends string, | ||
ParamType = string | number | boolean, | ||
> = Route extends `${infer Param}?` | ||
? { [K in Param]?: ParamType } | ||
: Route extends `${infer Param}*` | ||
? { [K in Param]?: ParamType } | ||
: Route extends `${infer Param}+` | ||
? { [K in Param]: ParamType } | ||
: { [K in Route]: ParamType }; | ||
|
||
/** | ||
* @description | ||
* Extract parameters from a route pattern, including handling parameter constraints and modifiers. | ||
* | ||
* This type recursively parses a route string and extracts parameters, considering optional('?'), | ||
* repeating('+', '*'), and required parameter modifiers. | ||
* | ||
* @template {string} Route - The route pattern string. | ||
* @template {string | number | boolean} ParamType - The type of the parameter values. | ||
* | ||
* @example | ||
* type T0 = ExtractRouteParams<'/users/:userId/posts/:postId'>; | ||
* // Result: { userId: string } & { postId: string } | ||
* | ||
* type T1 = ExtractRouteParams<'/users/:userId/posts/:postId', number>; | ||
* // Result: { userId: number } & { postId: number } | ||
* | ||
* type T2 = ExtractRouteParams<'/users/:userId(\\d+)', number>; | ||
* // Result: { userId: number } | ||
* | ||
* type T3 = ExtractRouteParams<'/search/:query+'>; | ||
* // Result: { query: string } | ||
* | ||
* type T4 = ExtractRouteParams<'/items/:itemId/:category?'> | ||
* // Result: { itemId: string } & { category?: string } | ||
*/ | ||
|
||
export type ExtractRouteParams< | ||
Route extends string, | ||
ParamType = string | number | boolean, | ||
> = string extends Route | ||
? { [K in Route]: ParamType } | ||
: Route extends `${infer Start}:${infer ParamWithOptionalRegExp}/${infer Rest}` | ||
? ParamWithOptionalRegExp extends `${infer Param}(${infer _RegExp})${infer Modifier extends ParameterModifier}` | ||
? ExtractRouteOptionalParam<`${Param}${Modifier}`, ParamType> & | ||
ExtractRouteParams<Rest, ParamType> | ||
: ExtractRouteOptionalParam<ParamWithOptionalRegExp, ParamType> & | ||
ExtractRouteParams<Rest, ParamType> | ||
: Route extends `${infer Start}:${infer ParamWithOptionalRegExp}` | ||
? ParamWithOptionalRegExp extends `${infer Param}(${infer _RegExp})${infer Modifier extends ParameterModifier}` | ||
? ExtractRouteOptionalParam<`${Param}${Modifier}`, ParamType> | ||
: ExtractRouteOptionalParam<`${ParamWithOptionalRegExp}`, ParamType> | ||
: {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export type { ExtractRouteParams } from './ExtractRouteParams'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { ExtractRouteParams } from '@/url-parser'; | ||
import { expectType } from 'tsd'; | ||
|
||
declare function extractRouteParams< | ||
Route extends string, | ||
ParamType = string, | ||
>(): ExtractRouteParams<Route, ParamType>; | ||
|
||
// Should correclty handle basic pattern | ||
expectType<{ userId: string } & { postId: string }>( | ||
extractRouteParams<'/users/:userId/posts/:postId'>() | ||
); | ||
|
||
expectType<{ userId: number } & { postId: number }>( | ||
extractRouteParams<'/users/:userId/posts/:postId', number>() | ||
); | ||
|
||
expectType<{ userId: boolean } & { postId: boolean }>( | ||
extractRouteParams<'/users/:userId/posts/:postId', boolean>() | ||
); | ||
|
||
// Should correctly handle optioanl parameter | ||
expectType<{ userId?: string }>(extractRouteParams<'/users/:userId?'>()); | ||
|
||
// Should correctly handle repetitive parameters | ||
expectType<{ filePath: string }>(extractRouteParams<'/files/:filePath+'>()); | ||
expectType<{ filePath?: string }>(extractRouteParams<'/files/:filePath*'>()); | ||
expectType<{ username: string }>( | ||
extractRouteParams<'/users/:username([a-z]+)'>() | ||
); | ||
|
||
// Should correctly handle regular expression parameters | ||
expectType<{ userId: string }>(extractRouteParams<'/users/:userId(\\d+)'>()); | ||
|
||
// Should correctly handle complex pattern | ||
expectType<{ userId?: string }>(extractRouteParams<'/users/:userId(\\d+)?'>()); | ||
expectType<{ filePath: string }>(extractRouteParams<'/files/:filePath(.*)+'>()); |