npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

string-ts

v2.4.0

Published

Strongly-typed string functions.

Readme

NPM Library size Code Coverage All Contributors

Strongly-typed string functions for all!

A demonstration of string-ts

😬 The problem

When you are working with literal strings, the string manipulation functions only work at the runtime level and the types don't follow those transformations. You end up losing type information and possibly having to cast the result.

const str = 'hello-world'
const result = str.replace('-', ' ') // you should use: as 'hello world'
//    ^? string

🤓 The solution

This library aims to solve this problem by providing a set of common functions that work with literal strings at both type and runtime level.

import { replace } from 'string-ts'

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

🔍 Why this matters

TypeScript yields the best static analysis when types are highly specific. Literals are more specific than type string. This library preserves literals (and unions of literals) after transformations, unlike most existing utility libraries (and built-in string methods.)

I still don't get the purpose of this library 🤔

In-depth example

In the below example, I want to get a strongly-typed, camel-case version of process.env. One flow results in a loose type, and the other results in a more precise type. This example should illustrate the highly-specific and flexible nature of string-ts.

import { deepCamelKeys } from 'string-ts'
import { camelCase, mapKeys } from 'lodash-es'
import z from 'zod'

const EnvSchema = z.object({
  NODE_ENV: z.string(),
})

function getEnvLoose() {
  const rawEnv = EnvSchema.parse(process.env)
  const env = mapKeys(rawEnv, (_v, k) => camelCase(k))
  //    ^? Dictionary<string>

  // `Dictionary<string>` is too loose
  // TypeScript is okay with this, 'abc' is expected to be of type `string`
  // This will have unexpected behavior at runtime
  console.log(env.abc)
}

function getEnvPrecise() {
  const rawEnv = EnvSchema.parse(process.env)
  const env = deepCamelKeys(rawEnv)
  //    ^? { nodeEnv: string }

  // Error: Property 'abc' does not exist on type '{ nodeEnv: string; }'
  // Our type is more specific, so TypeScript catches this error.
  // This mistake will be caught at compile time
  console.log(env.abc)
}

function main() {
  getEnvLoose()
  getEnvPrecise()
}

main()

📦 Installation

npm install string-ts

🌳 Tree shaking

string-ts has been designed with tree shaking in mind. We have tested it with build tools like Webpack, Vite, Rollup, etc.

👌 Supported TypeScript versions

string-ts currently only works on TypeScript v5+.

See also: Known limitations.

🪄 Native String Method Overrides

Extracting functions from string-ts is the recommended usage, but if you'd like to apply strongly-typed versions of native string methods project-wide, you can do so with a single import.

Inspired by ts-reset, this import overrides the native String.prototype type declarations, giving you strong typing for supported methods like charAt, startsWith, endsWith, replace, split, and more.

import 'string-ts/native'

const str = 'hello-world' as const

str.replace('-', '_')
//  ^? 'hello_world'

str.charAt(6)
//  ^? 'w'

str.startsWith('hello')
//  ^? true

str.split('-')
//  ^? ['hello', 'world']

This has minimal impact on type-checker performance. In our tests, TSC went from 17.21s to 17.41s.

Note: Only methods already supported by the library are typed. The length property cannot be strongly-typed as it's a read-only property, not a method.


📖 API


Runtime counterparts of native type utilities

capitalize

Capitalizes the first letter of a string. This is a runtime counterpart of Capitalize<T> from src/types.d.ts.

import { capitalize } from 'string-ts'

const str = 'hello world'
const result = capitalize(str)
//    ^ 'Hello world'

uncapitalize

Uncapitalizes the first letter of a string. This is a runtime counterpart of Uncapitalize<T> from src/types.d.ts.

import { uncapitalize } from 'string-ts'

const str = 'Hello world'
const result = uncapitalize(str)
//    ^ 'hello world'

Strongly-typed alternatives to native runtime utilities

charAt

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

import { charAt } from 'string-ts'

const str = 'hello world'
const result = charAt(str, 6)
//    ^ 'w'

concat

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

import { concat } from 'string-ts'

const result = concat('a', 'bc', 'def')
//    ^ 'abcdef'

endsWith

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

import { endsWith } from 'string-ts'

const result = endsWith('abc', 'c')
//    ^ true

See endsWithGuard for a type-guard counterpart that narrows the input string instead of returning a boolean.

includes

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

import { includes } from 'string-ts'

const result = includes('abcde', 'bcd')
//    ^ true

See includesGuard for a type-guard counterpart that narrows the input string instead of returning a boolean.

join

This function is a strongly-typed counterpart of Array.prototype.join.

import { join } from 'string-ts'

const str = ['hello', 'world']
const result = join(str, ' ')
//    ^ 'hello world'

length

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

import { length } from 'string-ts'

const str = 'hello'
const result = length(str)
//    ^ 5

padEnd

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

import { padEnd } from 'string-ts'

const str = 'hello'
const result = padEnd(str, 10, '=')
//    ^ 'hello====='

padStart

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

import { padStart } from 'string-ts'

const str = 'hello'
const result = padStart(str, 10, '=')
//    ^ '=====hello'

repeat

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

Note: for counts above 45 the return type falls back to string to avoid TypeScript's type-instantiation depth limit. See Known limitations.

import { repeat } from 'string-ts'

const str = 'abc'
const result = repeat(str, 3)
//    ^ 'abcabcabc'

replace

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

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

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 fully support Regex. Using a RegExp lookup will result in a loose typing.

import { replaceAll } from 'string-ts'

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

slice

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

import { slice } from 'string-ts'

const str = 'hello-world'
const result = slice(str, 6)
//    ^ 'world'
const result2 = slice(str, 1, 5)
//    ^ 'ello'
const result3 = slice(str, -5)
//    ^ 'world'

split

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

import { split } from 'string-ts'

const str = 'hello-world'
const result = split(str, '-')
//    ^ ['hello', 'world']

startsWith

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

import { startsWith } from 'string-ts'

const result = startsWith('abc', 'a')
//    ^ true

See startsWithGuard for a type-guard counterpart that narrows the input string instead of returning a boolean.

toLowerCase

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

import { toLowerCase } from 'string-ts'

const str = 'HELLO WORLD'
const result = toLowerCase(str)
//    ^ 'hello world'

toUpperCase

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

import { toUpperCase } from 'string-ts'

const str = 'hello world'
const result = toUpperCase(str)
//    ^ 'HELLO WORLD'

trim

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

import { trim } from 'string-ts'

const str = '  hello world  '
const result = trim(str)
//    ^ 'hello world'

trimEnd

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

import { trimEnd } from 'string-ts'

const str = '  hello world  '
const result = trimEnd(str)
//    ^ '  hello world'

trimStart

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

import { trimStart } from 'string-ts'

const str = '  hello world  '
const result = trimStart(str)
//    ^ 'hello world  '

Type guards

These are type-guard versions of includes, startsWith, and endsWith. Instead of returning a strongly-typed boolean, they narrow the input string — keeping only the members of a string-literal union that satisfy the check, in both branches of the condition.

Note: a TypeScript type predicate always surfaces a plain boolean to the caller, so these functions trade the literal true/false return of their counterparts for the ability to narrow. Reach for the plain function when you want the literal boolean, and for the *Guard function when you want narrowing.

includesGuard

This function is a type-guard version of includes.

import { includesGuard } from 'string-ts'

declare const reportType:
  | 'HouseCalendar'
  | 'SenateCalendar'
  | 'HouseFirstReading'

if (includesGuard(reportType, 'Calendar')) {
  reportType
  //  ^ 'HouseCalendar' | 'SenateCalendar'
} else {
  reportType
  //  ^ 'HouseFirstReading'
}

startsWithGuard

This function is a type-guard version of startsWith.

import { startsWithGuard } from 'string-ts'

declare const reportType: 'HouseCalendar' | 'SenateCalendar'

if (startsWithGuard(reportType, 'House')) {
  reportType
  //  ^ 'HouseCalendar'
}

endsWithGuard

This function is a type-guard version of endsWith.

import { endsWithGuard } from 'string-ts'

declare const reportType: 'HouseCalendar' | 'HouseFirstReading'

if (endsWithGuard(reportType, 'Calendar')) {
  reportType
  //  ^ 'HouseCalendar'
}

Strongly-typed alternatives to common loosely-typed functions

lowerCase

This function converts a string to lower case at both runtime and type levels. NOTE: this function will split by words and join them with " ", unlike toLowerCase.

import { lowerCase } from 'string-ts'

const str = 'HELLO-WORLD'
const result = lowerCase(str)
//    ^ 'hello world'

camelCase

This function converts a string to camelCase at both runtime and type levels.

import { camelCase } from 'string-ts'

const str = 'hello-world'
const result = camelCase(str)
//    ^ 'helloWorld'

constantCase

This function converts a string to CONSTANT_CASE at both runtime and type levels.

import { constantCase } from 'string-ts'

const str = 'helloWorld'
const result = constantCase(str)
//    ^ 'HELLO_WORLD'

delimiterCase

This function converts a string to a new case with a custom delimiter at both runtime and type levels.

import { delimiterCase } from 'string-ts'

const str = 'helloWorld'
const result = delimiterCase(str, '.')
//    ^ 'hello.World'

kebabCase

This function converts a string to kebab-case at both runtime and type levels.

import { kebabCase } from 'string-ts'

const str = 'helloWorld'
const result = kebabCase(str)
//    ^ 'hello-world'

pascalCase

This function converts a string to PascalCase at both runtime and type levels.

import { pascalCase } from 'string-ts'

const str = 'hello-world'
const result = pascalCase(str)
//    ^ 'HelloWorld'

snakeCase

This function converts a string to snake_case at both runtime and type levels.

import { snakeCase } from 'string-ts'

const str = 'helloWorld'
const result = snakeCase(str)
//    ^ 'hello_world'

titleCase

This function converts a string to Title Case at both runtime and type levels.

import { titleCase } from 'string-ts'

const str = 'helloWorld'
const result = titleCase(str)
//    ^ 'Hello World'

upperCase

This function converts a string to UPPER CASE at both runtime and type levels. NOTE: this function will split by words and join them with " ", unlike toUpperCase.

import { upperCase } from 'string-ts'

const str = 'hello-world'
const result = upperCase(str)
//    ^ 'HELLO WORLD'

reverse

This function reverses a string.

import { reverse } from 'string-ts'

const str = 'Hello StringTS!'
const result = reverse(str)
//    ^ '!TSgnirtS olleH'

truncate

This function truncates string if it's longer than the given maximum string length. The last characters of the truncated string are replaced with the omission string which defaults to "...".

import { truncate } from 'string-ts'

const str = '-20someVery-weird String'
const result = truncate(str, 8)
//    ^ '-20so...'

words

This function identifies the words in a string and returns a tuple of words split by separators, differences in casing, numbers, and etc.

import { words } from 'string-ts'

const str = '-20someVery-weird String'
const result = words(str)
//    ^ ['20', 'some', 'Very', 'weird', 'String']

Strongly-typed shallow transformation of objects

camelKeys

This function shallowly converts the keys of an object to camelCase at both runtime and type levels.

import { camelKeys } from 'string-ts'

const data = {
  'hello-world': {
    'foo-bar': 'baz',
  },
} as const
const result = camelKeys(data)
//    ^ { helloWorld: { 'foo-bar': 'baz' } }

constantKeys

This function shallowly converts the keys of an object to CONSTANT_CASE at both runtime and type levels.

import { constantKeys } from 'string-ts'

const data = {
  helloWorld: {
    fooBar: 'baz',
  },
} as const
const result = constantKeys(data)
//    ^ { 'HELLO_WORLD': { 'fooBar': 'baz' } }

delimiterKeys

This function shallowly converts the keys of an object to a new case with a custom delimiter at both runtime and type levels.

import { delimiterKeys } from 'string-ts'

const data = {
  'hello-world': {
    'foo-bar': 'baz',
  },
} as const
const result = delimiterKeys(data, '.')
//    ^ { 'hello.world': { 'foo-bar': 'baz' } }

kebabKeys

This function shallowly converts the keys of an object to kebab-case at both runtime and type levels.

import { kebabKeys } from 'string-ts'

const data = {
  helloWorld: {
    fooBar: 'baz',
  },
} as const
const result = kebabKeys(data)
//    ^ { 'hello-world': { fooBar: 'baz' } }

pascalKeys

This function shallowly converts the keys of an object to PascalCase at both runtime and type levels.

import { pascalKeys } from 'string-ts'

const data = {
  'hello-world': {
    'foo-bar': 'baz',
  },
} as const
const result = pascalKeys(data)
//    ^ { HelloWorld: { FooBar: 'baz' } }

snakeKeys

This function shallowly converts the keys of an object to snake_case at both runtime and type levels.

import { snakeKeys } from 'string-ts'

const data = {
  helloWorld: {
    fooBar: 'baz',
  },
} as const
const result = snakeKeys(data)
//    ^ { 'hello_world': { 'fooBar': 'baz' } }

replaceKeys

This function shallowly transforms the keys of an object by applying replace to each of its keys at both runtime and type levels.

import { replaceKeys } from 'string-ts'

const data = {
  helloWorld: {
    fooBar: 'baz',
  },
} as const
const result = replaceKeys(data, 'o', 'a')
//    ^ { 'hellaWorld': { 'fooBar': 'baz' } }

Strongly-typed deep transformation of objects

deepCamelKeys

This function recursively converts the keys of an object to camelCase at both runtime and type levels.

import { deepCamelKeys } from 'string-ts'

const data = {
  'hello-world': {
    'foo-bar': 'baz',
  },
} as const
const result = deepCamelKeys(data)
//    ^ { helloWorld: { fooBar: 'baz' } }

deepConstantKeys

This function recursively converts the keys of an object to CONSTANT_CASE at both runtime and type levels.

import { deepConstantKeys } from 'string-ts'

const data = {
  helloWorld: {
    fooBar: 'baz',
  },
} as const
const result = deepConstantKeys(data)
//    ^ { 'HELLO_WORLD': { 'FOO_BAR': 'baz' } }

deepDelimiterKeys

This function recursively converts the keys of an object to a new case with a custom delimiter at both runtime and type levels.

import { deepDelimiterKeys } from 'string-ts'

const data = {
  'hello-world': {
    'foo-bar': 'baz',
  },
} as const
const result = deepDelimiterKeys(data, '.')
//    ^ { 'hello.world': { 'foo.bar': 'baz' } }

deepKebabKeys

This function recursively converts the keys of an object to kebab-case at both runtime and type levels.

import { deepKebabKeys } from 'string-ts'

const data = {
  helloWorld: {
    fooBar: 'baz',
  },
} as const
const result = deepKebabKeys(data)
//    ^ { 'hello-world': { 'foo-bar': 'baz' } }

deepPascalKeys

This function recursively converts the keys of an object to PascalCase at both runtime and type levels.

import { deepPascalKeys } from 'string-ts'

const data = {
  'hello-world': {
    'foo-bar': 'baz',
  },
} as const
const result = deepPascalKeys(data)
//    ^ { HelloWorld: { FooBar: 'baz' } }

deepSnakeKeys

This function recursively converts the keys of an object to snake_case at both runtime and type levels.

import { deepSnakeKeys } from 'string-ts'

const data = {
  helloWorld: {
    fooBar: 'baz',
  },
} as const
const result = deepSnakeKeys(data)
//    ^ { 'hello_world': { 'foo_bar': 'baz' } }

Type utilities

All the functions presented in this API have associated type counterparts.

import type * as St from 'string-ts'

Native TS type utilities

Capitalize<'hello world'> // 'Hello world'
Lowercase<'HELLO WORLD'> // 'hello world'
Uppercase<'hello world'> // 'HELLO WORLD'

General type utilities from this library

St.CharAt<'hello world', 6> // 'w'
St.Concat<['a', 'bc', 'def']> // 'abcdef'
St.EndsWith<'abc', 'c'> // true
St.Includes<'abcde', 'bcd'> // true
St.Join<['hello', 'world'], '-'> // 'hello-world'
St.Length<'hello'> // 5
St.PadEnd<'hello', 10, '='> // 'hello====='
St.PadStart<'hello', 10, '='> // '=====hello'
St.Repeat<'abc', 3> // 'abcabcabc'
St.Replace<'hello-world', 'l', '1'> // 'he1lo-world'
St.ReplaceAll<'hello-world', 'l', '1'> // 'he11o-wor1d'
St.Reverse<'Hello World!'> // '!dlroW olleH'
St.Slice<'hello-world', -5> // 'world'
St.Split<'hello-world', '-'> // ['hello', 'world']
St.Trim<' hello world '> // 'hello world'
St.StartsWith<'abc', 'a'> // true
St.TrimEnd<' hello world '> // ' hello world'
St.TrimStart<' hello world '> // 'hello world '
St.Truncate<'hello world', 9, '[...]'> // 'hello[...]
St.Words<'hello-world'> // ['hello', 'world']

// Type-guard filters: keep the union members that satisfy the check
St.WhenIncludes<'abcde' | 'xyz', 'bcd'> // 'abcde'
St.WhenStartsWith<'abc' | 'xyz', 'a'> // 'abc'
St.WhenEndsWith<'abc' | 'xyz', 'c'> // 'abc'

Casing type utilities

Core

St.CamelCase<'hello-world'> // 'helloWorld'
St.ConstantCase<'helloWorld'> // 'HELLO_WORLD'
St.DelimiterCase<'hello world', '.'> // 'hello.world'
St.KebabCase<'helloWorld'> // 'hello-world'
St.PascalCase<'hello-world'> // 'HelloWorld'
St.SnakeCase<'helloWorld'> // 'hello_world'
St.TitleCase<'helloWorld'> // 'Hello World'
Missing types

Note that we do not include UpperCase and LowerCase types. These would be too close to the existing TS types Uppercase and Lowercase.

One could create either by doing like so:

type LowerCase<T extends string> = Lowercase<DelimiterCase<T, ' '>>
type UpperCase<T extends string> = Uppercase<DelimiterCase<T, ' '>>
// or
type LowerCase<T extends string> = ReturnType<typeof lowerCase<T>>
type UpperCase<T extends string> = ReturnType<typeof upperCase<T>>

Shallow object key transformation

St.CamelKeys<{
  'hello-world': { 'foo-bar': 'baz' }
}> // { helloWorld: { 'foo-bar': 'baz' } }
St.ConstantKeys<{
  helloWorld: { fooBar: 'baz' }
}> // { 'HELLO_WORLD': { fooBar: 'baz' } }
St.DelimiterKeys<{ 'hello-world': { 'foo-bar': 'baz' } }, '.'>
// { 'hello.world': { 'foo-bar': 'baz' } }
St.KebabKeys<{
  helloWorld: { fooBar: 'baz' }
}> // { 'hello-world': { fooBar: 'baz' } }
St.PascalKeys<{
  'hello-world': { 'foo-bar': 'baz' }
}> // { HelloWorld: { 'foo-bar': 'baz' } }
St.SnakeKeys<{
  helloWorld: { fooBar: 'baz' }
}> // { 'hello_world': { fooBar: 'baz' } }

Deep object key transformation

St.DeepCamelKeys<{
  'hello-world': { 'foo-bar': 'baz' }
}> // { helloWorld: { fooBar: 'baz' } }
St.DeepConstantKeys<{
  helloWorld: { fooBar: 'baz' }
}> // { 'HELLO_WORLD': { 'FOO_BAR': 'baz' } }
St.DeepDelimiterKeys<
  {
    'hello-world': { 'foo-bar': 'baz' }
  },
  '.'
> // { 'hello.world': { 'foo.bar': 'baz' } }
St.DeepKebabKeys<{
  helloWorld: { fooBar: 'baz' }
}> // { 'hello-world': { 'foo-bar': 'baz' } }
St.DeepPascalKeys<{
  'hello-world': { 'foo-bar': 'baz' }
}> // { HelloWorld: { FooBar: 'baz' } }
St.DeepSnakeKeys<{
  helloWorld: { fooBar: 'baz' }
}> // { 'hello_world': { 'foo_bar': 'baz' } }

Other exported type utilities

St.IsDigit<'a'> // false
St.IsDigit<'1'> // true
St.IsLetter<'a'> // true
St.IsLetter<'1'> // false
St.IsLower<'a'> // true
St.IsLower<'A'> // false
St.IsUpper<'a'> // false
St.IsUpper<'A'> // true
St.IsSeparator<' '> // true
St.IsSeparator<'-'> // true
St.IsSeparator<'a'> // false
St.IsSpecial<'a'> // false
St.IsSpecial<'!'> // true
St.IsSpecial<' '> // false

Runtime-only utilities

deepTransformKeys

This function recursively converts the keys of an object to a custom format, but only at runtime level.

import { deepTransformKeys, toUpperCase } from 'string-ts'

const data = { helloWorld: 'baz' } as const

type MyType<T> = { [K in keyof T as Uppercase<K>]: T[K] }
const result = deepTransformKeys(data, toUpperCase) as MyType<typeof data>
//    ^ { 'HELLOWORLD': 'baz' }

Known limitations

ASCII only

string-ts only works with common ASCII characters. We don't plan to support international characters or emojis.

Type-level recursion depth

TypeScript has an internal limit on how deeply it can evaluate recursive types. Some string-ts types rely on recursion, so very large inputs will cause the type to fall back to string (or a template literal like `${string}hello`) instead of computing the exact literal.

| Function / Type | Exact-literal limit | Behaviour beyond limit | |---|---|---| | repeat / Repeat | count ≤ 45 | Returns string | | padStart / PadStart | padding ≤ 45 chars | Returns `${string}<original>` | | padEnd / PadEnd | padding ≤ 45 chars | Returns `<original>${string}` |

Runtime behaviour is unaffected — only the inferred type widens.

🎙️ Interview

For a deeper dive into the code, reasoning, and how this library came to be, check out this interview with the author of StringTs on the Michigan TypeScript Meetup.

StringTs on Michigan TS

🐝 Contributors

Thanks goes to these wonderful people (emoji key):

This project follows the all-contributors specification. Contributions of any kind welcome!

StringTs logo by NUMI:

🫶 Acknowledgements

This library got a lot of inspiration from libraries such as lodash, ts-reset, type-fest, HOTScript, and many others.