식별할 수 있는 문자열(문자열 리터럴) 확인하는 방법
과거 2022.4.22에 작성했던 글
string extends T를 추가로 검사하면
string은 문자열 리터럴 타입을 상속하지 않으므로
string과 문자열 리터럴 타입을 구분할 수 있게 된다.
이것을 활용하여 다음과 같은 유틸리티를 만들었다.
import { generatePath } from 'react-router'
import type { ParamParseKey } from 'react-router/lib/router'
import type { IdentifiableString } from '~/types/utilityTypes'
// ParamParseKey는 :로 시작하는 동적 라우트 키 값의 이름을 뽑아온다.
// ParamParseKey<"/:userName/aaa/:blogId/edit"> -> 'userName' | 'blogId'
export const routeMatch = {
login: '/login',
categoryList: '/:userName/category',
category: '/:userName/category/:categoryId',
categoryPostList: '/:userName/category/:categoryId/list/:postId',
newPost: '/:userName/post/new',
editPost: '/:userName/post/:postId/edit',
} as const
type RouterPathFn<T extends string> = (
...params: IdentifiableString<ParamParseKey<T>> extends true
? [
{
[key in ParamParseKey<T>]: string
}
]
: []
) => string
const makePathFunc =
<Path extends string>(patternPath: Path): RouterPathFn<Path> =>
(...params) =>
generatePath(patternPath, ...params)
type RouteMatch = typeof routeMatch
type PathNames = keyof RouteMatch
export const routerPaths = Object.fromEntries(
Object.entries(routeMatch).map(
([pathName, path], cv) => [pathName, makePathFunc(path)]
)
) as {
[key in PathNames]: RouterPathFn<RouteMatch[key]>
}
const categoryListPath = routerPaths.categoryList({ userName: 'gururu' })
// => '/gururu/category'
이러면 routeMatch에 경로에 해당하는 문자열만 추가해주면 알아서 routerPaths에 해당하는 generator 함수가 만들어진다.