String
The string category identifies string, string literals and template literals, and provides a few
type-level string operations. The predicates follow the usual
type branching contract, so each one can act as a boolean check, as a
filter, or as a branch selector for your own types.
IsString and IsNotString
Section titled “IsString and IsNotString”type IsString<T, $O extends IsString.$Options = {}>type IsNotString<T, $O extends IsNotString.$Options = {}>IsString<T> is true for string and for any string literal.
type R1 = IsString<string> // truetype R2 = IsString<'a'> // truetype R3 = IsString<1> // falsetype R4 = IsString<string | boolean> // boolean$Options combines $Selection.Options, $Distributive.Options, $Exact.Options and input options for
any, unknown, never and void. That means selection: 'filter' returns the input instead of a
boolean, and distributive: false stops a union from being evaluated member by member:
type R1 = IsString<'a', { selection: 'filter' }> // 'a'type R2 = IsString<string | boolean, { selection: 'filter' }> // stringtype R3 = IsString<string | 1, { distributive: false }> // falseIsNotString<T> is the negation, and its filter selection keeps everything that is not a string:
type R1 = IsNotString<1> // truetype R2 = IsNotString<'a'> // falseSee Options for what selection, distributive and exact mean, and
type branching for $any, $unknown, $never, $void, $then,
$else and the IsString.$Branch selectors.
IsStringLiteral and IsNotStringLiteral
Section titled “IsStringLiteral and IsNotStringLiteral”type IsStringLiteral<T, $O extends IsStringLiteral.$Options = {}>type IsNotStringLiteral<T, $O extends IsNotStringLiteral.$Options = {}>Distinguishes a literal from the wide string type. Template literals count as literals by default.
type R1 = IsStringLiteral<'a'> // truetype R2 = IsStringLiteral<`${number}`> // truetype R3 = IsStringLiteral<string> // falseUse exact: true to reject template literals and accept only plain literals:
type R1 = IsStringLiteral<`${number}`> // truetype R2 = IsStringLiteral<`${number}`, { exact: true }> // falseIsTemplateLiteral and IsNotTemplateLiteral
Section titled “IsTemplateLiteral and IsNotTemplateLiteral”type IsTemplateLiteral<T, $O extends IsTemplateLiteral.$Options = {}>type IsNotTemplateLiteral<T, $O extends IsNotTemplateLiteral.$Options = {}>The mirror image of the above: only template literals pass.
type R1 = IsTemplateLiteral<`a${number}`> // truetype R2 = IsTemplateLiteral<'foo'> // falsetype R3 = IsTemplateLiteral<string> // false
type R4 = IsTemplateLiteral<`${number}`, { selection: 'filter' }> // `${number}`type R5 = IsTemplateLiteral<'a', { selection: 'filter' }> // neverStringIncludes
Section titled “StringIncludes”type StringIncludes<Subject extends string, Search extends string, Then = true, Else = false>Checks whether Subject contains Search. This type predates type branching and takes plain
Then/Else parameters instead of an options object.
type R1 = StringIncludes<'abc', 'a'> // truetype R2 = StringIncludes<'abc', 'd'> // falsetype R3 = StringIncludes<'abc', 'd', 'yes', 'no'> // 'no'StringSplit
Section titled “StringSplit”type StringSplit<Subject extends string, Seperator extends string>Splits Subject on Seperator and returns a tuple. An empty separator splits into characters.
type R1 = StringSplit<'abc', ''> // ['a', 'b', 'c']type R2 = StringSplit<'a.b.c', '.'> // ['a', 'b', 'c']type R3 = StringSplit<'abc', 'b'> // ['a', 'c']StringPlus namespace
Section titled “StringPlus namespace”StringPlus exposes the same operations under shorter names, for when the prefixed names read poorly at
the call site.
import type { StringPlus } from 'type-plus'
type R1 = StringPlus.Includes<'abc', 'a'> // truetype R2 = StringPlus.Split<'abc', ''> // ['a', 'b', 'c']StringPlus.Includes takes the type branching options object
rather than the positional Then/Else that StringIncludes still uses.
type R = StringPlus.Includes<'abc', 'd', { $then: 'yes'; $else: 'no' }> // 'no'type R = StringPlus.Includes<'abc', 'a', { selection: 'filter' }> // 'abc'type R = StringPlus.Includes<'abc', 'd', { selection: 'filter' }> // never$ExtractManipulatedString
Section titled “$ExtractManipulatedString”type $ExtractManipulatedString<T extends string>A type util (the $ prefix marks it as building material rather than an everyday type). It unwraps the
intrinsic string manipulation types — Uppercase, Lowercase, Capitalize and Uncapitalize — to
recover the string being manipulated. IsStringLiteral uses it to see through those wrappers.
It only sees a wrapper that TypeScript has not already resolved. Applied to a literal, the intrinsic evaluates first and there is nothing left to unwrap:
type R1 = $ExtractManipulatedString<Uppercase<string>> // stringtype R2 = $ExtractManipulatedString<Uppercase<'abc'>> // 'ABC'type R3 = $ExtractManipulatedString<'abc'> // 'abc'Reference
Section titled “Reference”| Type | Description |
|---|---|
IsString<T, $O> |
T is string or a string literal |
IsNotString<T, $O> |
T is neither string nor a string literal |
IsStringLiteral<T, $O> |
T is a string literal (template literals included unless exact: true) |
IsNotStringLiteral<T, $O> |
T is not a string literal |
IsTemplateLiteral<T, $O> |
T is a template literal |
IsNotTemplateLiteral<T, $O> |
T is not a template literal |
StringIncludes<S, Search, Then, Else> |
S contains Search |
StringSplit<S, Seperator> |
split S into a tuple |
StringPlus.Includes<S, Search, $O> / StringPlus.Split<S, Seperator> |
namespaced aliases of the two above; Includes takes $O |
$ExtractManipulatedString<T> |
unwrap Uppercase/Lowercase/Capitalize/Uncapitalize |
Source: src/string.