Skip to content

Commit

Permalink
refactor: replace with regex (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
jly36963 committed Oct 5, 2023
1 parent 48d40cd commit 6f974d4
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 21 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ npm install string-ts
```

## 👌 Supported TypeScript Versions

`string-ts` currently only works on TypeScript v5+.

It also only work with common ASCII characters characters. We don't plan to support international characters or emojis.
Expand Down Expand Up @@ -284,29 +285,33 @@ const result = repeat(str, 3)

This function is a strongly-typed counterpart of `String.prototype.replace`.

_Warning: this is a partial implementation as we don't support Regex._
_Warning: this is a partial implementation, as we don't fully support Regex. Using a RegExp lookup will result in a loose typing._

```ts
import { replace } from 'string-ts'

const str = 'hello-world-'
const result = replace(str, '-', ' ')
// ^ 'hello world-'
const looselyTypedResult = replace(str, /-/, ' ')
// ^ string
```

### replaceAll

This function is a strongly-typed counterpart of `String.prototype.replaceAll`.
It also has a polyfill for runtimes older than ES2021.

_Warning: this is a partial implementation as we don't support Regex._
_Warning: this is a partial implementation, as we don't fully support Regex. Using a RegExp lookup will result in a loose typing._

```ts
import { replaceAll } from 'string-ts'

const str = 'hello-world-'
const result = replaceAll(str, '-', ' ')
// ^ 'hello world '
const looselyTypedResult = replaceAll(str, /-/g, ' ')
// ^ string
```

### slice
Expand Down
14 changes: 14 additions & 0 deletions src/primitives.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,12 @@ describe('primitives', () => {
expect(result).toEqual('somenice string')
type test = Expect<Equal<typeof result, 'somenice string'>>
})
test('should replace chars but not at type level when using RegExp', () => {
const data = 'some nice string'
const result = subject.replace(data, /nice /)
expect(result).toEqual('some string')
type test = Expect<Equal<typeof result, string>>
})
})

describe('replaceAll', () => {
Expand All @@ -295,6 +301,14 @@ describe('primitives', () => {
expect(result).toEqual('some@nice@string')
type test = Expect<Equal<typeof result, 'some@nice@string'>>
})

test('should replace chars but not at type level when using RegExp', () => {
const data = 'some nice string'
const result = subject.replaceAll(data, / /g, '-')
expect(result).toEqual('some-nice-string')
// Note: `string` instead of `some-nice-string`
type test = Expect<Equal<typeof result, string>>
})
})

describe('replaceAll polyfill', () => {
Expand Down
41 changes: 22 additions & 19 deletions src/primitives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,12 +212,13 @@ function repeat<T extends string, N extends number = 0>(
*/
type Replace<
sentence extends string,
lookup extends string,
lookup extends string | RegExp,
replacement extends string = '',
> = sentence extends `${infer rest}${lookup}${infer rest2}`
? `${rest}${replacement}${rest2}`
: sentence

> = lookup extends string
? sentence extends `${infer rest}${lookup}${infer rest2}`
? `${rest}${replacement}${rest2}`
: sentence
: string
/**
* A strongly-typed version of `String.prototype.replace`.
* @param sentence the sentence to replace.
Expand All @@ -226,11 +227,11 @@ type Replace<
* @returns the replaced string in both type level and runtime.
* @example replace('hello world', 'l', '1') // 'he1lo world'
*/
function replace<T extends string, S extends string, R extends string = ''>(
sentence: T,
lookup: S,
replacement: R = '' as R,
) {
function replace<
T extends string,
S extends string | RegExp,
R extends string = '',
>(sentence: T, lookup: S, replacement: R = '' as R) {
return sentence.replace(lookup, replacement) as Replace<T, S, R>
}

Expand All @@ -242,11 +243,13 @@ function replace<T extends string, S extends string, R extends string = ''>(
*/
type ReplaceAll<
sentence extends string,
lookup extends string,
lookup extends string | RegExp,
replacement extends string = '',
> = sentence extends `${infer rest}${lookup}${infer rest2}`
? `${rest}${replacement}${ReplaceAll<rest2, lookup, replacement>}`
: sentence
> = lookup extends string
? sentence extends `${infer rest}${lookup}${infer rest2}`
? `${rest}${replacement}${ReplaceAll<rest2, lookup, replacement>}`
: sentence
: string

/**
* A strongly-typed version of `String.prototype.replaceAll`.
Expand All @@ -256,11 +259,11 @@ type ReplaceAll<
* @returns the replaced string in both type level and runtime.
* @example replaceAll('hello world', 'l', '1') // 'he11o wor1d'
*/
function replaceAll<T extends string, S extends string, R extends string = ''>(
sentence: T,
lookup: S,
replacement: R = '' as R,
) {
function replaceAll<
T extends string,
S extends string | RegExp,
R extends string = '',
>(sentence: T, lookup: S, replacement: R = '' as R) {
// Only supported in ES2021+
if (typeof sentence.replaceAll === 'function') {
return sentence.replaceAll(lookup, replacement) as ReplaceAll<T, S, R>
Expand Down

0 comments on commit 6f974d4

Please sign in to comment.