String#matchAll should return iterable of RegExpExecArray instead of RegExpMatchArray
See original GitHub issueTypeScript Version: 3.7 (issue is with lib typing)
Search Terms: regex, matchall, es2020
Code
const matches = Array.from('xxx'.matchAll(/x/g));
matches[0].index; // TS reports index may be undefined, when it should always be defined
Currently matchAll
returns an iterable of RegExpMatchArray
. However, the index
and input
properties on RegExpMatchArray
are optional because String#match
returns a match object without those if the regex has the global flag (https://github.com/microsoft/TypeScript/issues/35157).
matchAll
on the other hand doesnโt have the same behavior, so it should use RegExpExecArray
where both of those properties are non-optional (or maybe create a RegExpMatchAllArray
type)
> Array.from('xxx'.matchAll(/x/g))
[
[ 'x', index: 0, input: 'xxx', groups: undefined ],
[ 'x', index: 1, input: 'xxx', groups: undefined ],
[ 'x', index: 2, input: 'xxx', groups: undefined ]
]
> Array.from('xxx'.matchAll(/a/g))
[]
> Array.from('aaa'.matchAll(/x/g))
[]
Expected behavior:
input
and index
on the match objects are not optional
Actual behavior:
TS reports that input
and index
may be optional
Playground Link: (Canโt use playground since lib cannot be configured)
Related Issues: https://github.com/microsoft/TypeScript/pull/30936 introduced String#matchAll
Issue Analytics
- State:
- Created 4 years ago
- Reactions:23
- Comments:5 (1 by maintainers)
Top GitHub Comments
According to the spec,
String#matchAll
actually executes with the semantics ofRegExp#exec
instead ofString#match
.So, OP is correct, the return type of
String#matchAll
should beIterableIterator<RegExpExecArray>
, not the currentIterableIterator<RegExpMatchArray>
.A regex given to
.matchAll()
will always be global. JavaScript throws an error if you attempt to pass it a non-global regex. Thus, unlike the return value of.match()
, the return value of.matchAll()
is always guaranteed to have.index
and.input
.I think the types for
.match()
make sense given that TypeScript has a limited understanding of regex flags and.match()
has a return type that is conditional on those flags, but the flags and limitations surrounding them are irrelevant to.matchAll()
, as the only possible return value from.matchAll()
is a type where.index
and.input
are required (always present and non-nullable).