Skip to content

Commit c78c4e1

Browse files
committed
fix(types): include flags in generated RegExp type
1 parent 60a92dd commit c78c4e1

File tree

3 files changed

+44
-14
lines changed

3 files changed

+44
-14
lines changed

src/core/types/magic-regexp.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
1-
const MagicRegExpSymbol = Symbol('MagicRegExp')
1+
const NamedGroups = Symbol('NamedGroups')
2+
const Value = Symbol('Value')
3+
const Flags = Symbol('Flags')
24

3-
export type MagicRegExp<Value extends string, T = never> = RegExp & {
4-
[MagicRegExpSymbol]: T & Value
5+
export type MagicRegExp<
6+
Value extends string,
7+
NamedGroups extends string | never = never,
8+
Flags extends string | never = never
9+
> = RegExp & {
10+
[NamedGroups]: NamedGroups
11+
[Value]: Value
12+
[Flags]: Flags
513
}
614

7-
type ExtractGroups<T extends MagicRegExp<string, string>> = T extends MagicRegExp<string, infer V>
15+
type ExtractGroups<T extends MagicRegExp<string, string, string>> = T extends MagicRegExp<
16+
string,
17+
infer V,
18+
string
19+
>
820
? V
921
: never
1022

11-
export type MagicRegExpMatchArray<T extends MagicRegExp<string, string>> = Omit<
23+
export type MagicRegExpMatchArray<T extends MagicRegExp<string, string, string>> = Omit<
1224
RegExpMatchArray,
1325
'groups'
1426
> & {

src/index.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
import type { Flag } from './core/flags'
22
import { Input, exactly } from './core/inputs'
3+
import type { Join } from './core/types/join'
34
import type { MagicRegExp, MagicRegExpMatchArray } from './core/types/magic-regexp'
45

5-
export const createRegExp = <Value extends string, NamedGroups extends string = never>(
6+
export const createRegExp = <
7+
Value extends string,
8+
NamedGroups extends string = never,
9+
Flags extends Flag[] = never[]
10+
>(
611
raw: Input<Value, NamedGroups> | Value,
7-
flags?: Flag[] | string | Set<Flag>
12+
flags?: [...Flags] | string | Set<Flag>
813
) =>
914
new RegExp(exactly(raw).toString(), [...(flags || '')].join('')) as MagicRegExp<
10-
`/${Value}/`,
11-
NamedGroups
15+
`/${Value}/${Join<Flags, '', ''>}`,
16+
NamedGroups,
17+
Flags[number]
1218
>
1319

1420
export * from './core/flags'
@@ -18,11 +24,9 @@ export * from './core/types/magic-regexp'
1824
// Add additional overload to global String object types to allow for typed capturing groups
1925
declare global {
2026
interface String {
21-
match<T extends string, R extends MagicRegExp<any, T>>(
22-
regexp: R
23-
): MagicRegExpMatchArray<R> | null
27+
match<R extends MagicRegExp<string, string, string>>(regexp: R): MagicRegExpMatchArray<R> | null
2428

25-
matchAll<T extends string, R extends MagicRegExp<any, T>>(
29+
matchAll<R extends MagicRegExp<string, string, string>>(
2630
regexp: R
2731
): IterableIterator<MagicRegExpMatchArray<R>>
2832
}

test/index.test.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
import { expect, it, describe } from 'vitest'
22
import { expectTypeOf } from 'expect-type'
33

4-
import { anyOf, char, createRegExp, exactly, global, digit, MagicRegExpMatchArray } from '../src'
4+
import {
5+
anyOf,
6+
char,
7+
createRegExp,
8+
exactly,
9+
global,
10+
digit,
11+
multiline,
12+
MagicRegExp,
13+
MagicRegExpMatchArray,
14+
} from '../src'
515
import { createInput } from '../src/core/internal'
616

717
describe('magic-regexp', () => {
@@ -11,6 +21,10 @@ describe('magic-regexp', () => {
1121
expect(regExp.test('thing')).toBeTruthy()
1222
expect(regExp.lastIndex).toMatchInlineSnapshot('4')
1323
})
24+
it('collects flag type', () => {
25+
const re = createRegExp('.', [global, multiline])
26+
expectTypeOf(re).toEqualTypeOf<MagicRegExp<'/./gm', never, 'g' | 'm'>>()
27+
})
1428
})
1529

1630
describe('inputs', () => {

0 commit comments

Comments
 (0)