목표
SELECT * FROM table WHERE id = {userId} AND name = {userName}
꼴의 스트링에서
{ userId : any; userName: any}
형태로 추출하는 타입 작성
주의사항
- 아래 타입과 같은 수준의 nesting은 옛날 타입스크립트 버전에서 호환되지 않을 수 있으므로,
반드시 타입스크립트 5.x.x 이상 버전을 사용해야 한다.
→ package.json/devDependencies/typescript 확인
Type
type Trim<T extends string, Acc extends string = '', Separator extends string = ' '>
= T extends `${infer Char}${infer Rest}`
? (Char extends Separator
? Trim<Rest, Acc>
: Trim<Rest, `${Acc}${Char}`>)
: (T extends ''
? Acc
: never);
type TrimComments<T extends string> =
T extends `${infer Head}#${any}\\n${infer Tail}`
? TrimComments<`${Head}\\n${Tail}`>
: T extends `${infer Head}--${any}\\n${infer Tail}`
? TrimComments<`${Head}\\n${Tail}`>
: T extends `${infer Head}/*${any}*/${infer Tail}`
? TrimComments<`${Head}${Tail}`>
// : T extends `${infer Head}#${any}\\r\\n${infer Tail}`
// ? TrimComments<`${Head}\\r\\n${Tail}`>
// : T extends `${infer Head}--${any}\\r\\n${infer Tail}`
// ? TrimComments<`${Head}\\r\\n${Tail}`>
: T;
type ParseQueryBegin<T extends string>
= T extends `${string}{${infer I}}${infer Tail extends string}` ?
{ i: I, tail: Tail } :
never;
type ParseQueryRecur<T extends { i: string, tail: string }>
= T['tail'] extends `${string}{${infer I}}${infer TailNext extends string}` ?
ParseQueryRecur<{ i: T['i'] | I, tail: TailNext }> :
T['i'];
type ParseQueryToInputUnion<T extends string> = ParseQueryRecur<ParseQueryBegin<T>>;
export type ExtractFromQuery<T extends string>
= Record<
ParseQueryToInputUnion<
Trim<
TrimComments<T>
>
>,
any
>;
Examples
/*{
id: any;
pw: any;
nick: any;
}*/
type ExampleA = ExtractFromQuery<"SELECT FROM {i d} AND {pw} AND {nick} GG {id}">;
/*{
id: any;
pw: any;
nick: any;
createDate: any;
}*/
type ExampleB = ExtractFromQuery<`
SELECT abc, def
FROM table /* {블록코멘트} */
WHERE id = {id} AND -- {라인코멘트1}
pw = {pw} AND # {라인코멘트2}
nick = {nick} AND
create_date = {createDate} AND
parent_id = {id} # 중복 컬럼: {id}
`>;
function RunQuery<TQry extends string>(query: TQry, input: ExtractFromQuery<TQry>) {}
RunQuery('SELECT * FROM table WHERE id={id} AND name={name}', { id: 'a', name: 123 })