0
# Strings and Text
1
2
String-specific validation including empty strings, whitespace detection, numeric strings, URL strings, and text content validation.
3
4
## Capabilities
5
6
### String Emptiness Checking
7
8
Check if strings are empty or contain only whitespace.
9
10
```typescript { .api }
11
/**
12
* Check if value is an empty string
13
* @param value - Value to check
14
* @returns True if value is empty string
15
*/
16
function isEmptyString(value: unknown): value is '';
17
18
/**
19
* Check if value is empty string or contains only whitespace
20
* @param value - Value to check
21
* @returns True if value is empty or whitespace string
22
*/
23
function isEmptyStringOrWhitespace(value: unknown): value is '' | Whitespace;
24
25
type Whitespace = ' '; // Represents whitespace-only strings
26
```
27
28
**Usage Examples:**
29
30
```typescript
31
import is from '@sindresorhus/is';
32
33
is.emptyString(''); // => true
34
is.emptyString('hello'); // => false
35
is.emptyString(null); // => false
36
37
is.emptyStringOrWhitespace(''); // => true
38
is.emptyStringOrWhitespace(' '); // => true
39
is.emptyStringOrWhitespace('\t\n'); // => true
40
is.emptyStringOrWhitespace('hello'); // => false
41
42
// Type guard usage
43
function processInput(input: unknown) {
44
if (is.string(input) && !is.emptyStringOrWhitespace(input)) {
45
// input is now typed as non-empty string
46
return input.trim().toUpperCase();
47
}
48
throw new Error('Input must be a non-empty string');
49
}
50
```
51
52
### Non-empty String Checking
53
54
Check if strings contain content or meaningful text.
55
56
```typescript { .api }
57
/**
58
* Check if value is a non-empty string
59
* @param value - Value to check
60
* @returns True if value is non-empty string
61
*/
62
function isNonEmptyString(value: unknown): value is NonEmptyString;
63
64
/**
65
* Check if value is non-empty string and not just whitespace
66
* @param value - Value to check
67
* @returns True if value is non-empty string with content
68
*/
69
function isNonEmptyStringAndNotWhitespace(value: unknown): value is NonEmptyString;
70
71
type NonEmptyString = string & {0: string}; // String with at least one character
72
```
73
74
**Usage Examples:**
75
76
```typescript
77
import is from '@sindresorhus/is';
78
79
is.nonEmptyString('hello'); // => true
80
is.nonEmptyString(' '); // => true (has characters, even if whitespace)
81
is.nonEmptyString(''); // => false
82
83
is.nonEmptyStringAndNotWhitespace('hello'); // => true
84
is.nonEmptyStringAndNotWhitespace('hello world'); // => true
85
is.nonEmptyStringAndNotWhitespace(' '); // => false
86
is.nonEmptyStringAndNotWhitespace(''); // => false
87
88
// Filtering arrays
89
const values = ['property1', '', null, 'property2', ' ', undefined];
90
const validStrings = values.filter(is.nonEmptyStringAndNotWhitespace);
91
console.log(validStrings); // ['property1', 'property2']
92
93
// Type guard usage
94
function createSlug(title: unknown) {
95
if (is.nonEmptyStringAndNotWhitespace(title)) {
96
// title is now typed as NonEmptyString with guaranteed content
97
return title.toLowerCase().replace(/\s+/g, '-');
98
}
99
throw new Error('Title must be a non-empty string with content');
100
}
101
```
102
103
### Whitespace String Checking
104
105
Check if a string contains only whitespace characters.
106
107
```typescript { .api }
108
/**
109
* Check if value is a string containing only whitespace
110
* @param value - Value to check
111
* @returns True if value is whitespace-only string
112
*/
113
function isWhitespaceString(value: unknown): value is Whitespace;
114
```
115
116
**Usage Examples:**
117
118
```typescript
119
import is from '@sindresorhus/is';
120
121
is.whitespaceString(' '); // => true
122
is.whitespaceString('\t\n\r '); // => true
123
is.whitespaceString(''); // => false (empty, not whitespace)
124
is.whitespaceString('hello'); // => false
125
is.whitespaceString(' hello '); // => false (contains non-whitespace)
126
127
// Type guard usage
128
function normalizeText(text: unknown) {
129
if (is.string(text)) {
130
if (is.whitespaceString(text)) {
131
return ''; // Convert whitespace-only to empty
132
}
133
return text.trim();
134
}
135
return null;
136
}
137
```
138
139
### Numeric String Validation
140
141
Check if a string represents a valid number.
142
143
```typescript { .api }
144
/**
145
* Check if string represents a valid number
146
* @param value - Value to check
147
* @returns True if value is numeric string
148
*/
149
function isNumericString(value: unknown): value is `${number}`;
150
```
151
152
**Usage Examples:**
153
154
```typescript
155
import is from '@sindresorhus/is';
156
157
is.numericString('42'); // => true
158
is.numericString('3.14'); // => true
159
is.numericString('-123'); // => true
160
is.numericString('1e10'); // => true
161
is.numericString('Infinity'); // => true
162
is.numericString('-Infinity'); // => true
163
164
is.numericString('NaN'); // => false
165
is.numericString('42px'); // => false
166
is.numericString(''); // => false
167
is.numericString(' '); // => false
168
169
// Type guard usage
170
function parseUserInput(input: unknown) {
171
if (is.string(input) && is.numericString(input)) {
172
// input is typed as `${number}`
173
return Number(input);
174
}
175
return null;
176
}
177
178
// Form validation
179
function validateNumberField(field: unknown) {
180
if (is.nonEmptyStringAndNotWhitespace(field) && is.numericString(field)) {
181
const num = Number(field);
182
return { valid: true, value: num };
183
}
184
return { valid: false, error: 'Must be a valid number' };
185
}
186
```
187
188
### URL String Validation
189
190
Check if a string is a valid URL.
191
192
```typescript { .api }
193
/**
194
* Check if string is a valid URL
195
* @param value - Value to check
196
* @returns True if value is valid URL string
197
*/
198
function isUrlString(value: unknown): value is string;
199
```
200
201
**Usage Examples:**
202
203
```typescript
204
import is from '@sindresorhus/is';
205
206
is.urlString('https://example.com'); // => true
207
is.urlString('http://localhost:3000'); // => true
208
is.urlString('ftp://files.example.com'); // => true
209
is.urlString('mailto:user@example.com'); // => true
210
211
is.urlString('example.com'); // => false (no protocol)
212
is.urlString('https://'); // => false (incomplete)
213
is.urlString('not a url'); // => false
214
215
// Type guard usage
216
function openUrl(url: unknown) {
217
if (is.urlString(url)) {
218
// url is now typed as string and guaranteed to be valid URL
219
window.open(url, '_blank');
220
} else {
221
throw new Error('Invalid URL provided');
222
}
223
}
224
225
// URL validation with additional checks
226
function validateWebUrl(url: unknown) {
227
if (is.urlString(url)) {
228
const urlObj = new URL(url);
229
if (urlObj.protocol === 'https:' || urlObj.protocol === 'http:') {
230
return urlObj;
231
}
232
throw new Error('Only HTTP and HTTPS URLs are allowed');
233
}
234
throw new Error('Invalid URL format');
235
}
236
```
237
238
## Usage Patterns
239
240
### Form Field Validation
241
242
```typescript
243
import is from '@sindresorhus/is';
244
245
interface FormData {
246
name: string;
247
email: string;
248
age: number;
249
website?: string;
250
}
251
252
function validateForm(data: Record<string, unknown>): FormData {
253
const errors: string[] = [];
254
255
// Name validation
256
if (!is.nonEmptyStringAndNotWhitespace(data.name)) {
257
errors.push('Name is required and cannot be empty');
258
}
259
260
// Email validation (basic)
261
if (!is.nonEmptyStringAndNotWhitespace(data.email) || !data.email.includes('@')) {
262
errors.push('Valid email is required');
263
}
264
265
// Age validation
266
let age: number;
267
if (is.numericString(data.age)) {
268
age = Number(data.age);
269
} else if (is.number(data.age)) {
270
age = data.age;
271
} else {
272
errors.push('Age must be a number');
273
}
274
275
// Website validation (optional)
276
let website: string | undefined;
277
if (data.website !== undefined && data.website !== '') {
278
if (is.urlString(data.website)) {
279
website = data.website;
280
} else {
281
errors.push('Website must be a valid URL');
282
}
283
}
284
285
if (errors.length > 0) {
286
throw new Error(errors.join(', '));
287
}
288
289
return {
290
name: data.name as string,
291
email: data.email as string,
292
age: age!,
293
website
294
};
295
}
296
```
297
298
### Text Processing
299
300
```typescript
301
import is from '@sindresorhus/is';
302
303
function cleanTextArray(texts: unknown[]): string[] {
304
return texts
305
.filter(is.string) // Only strings
306
.filter(is.nonEmptyStringAndNotWhitespace) // With content
307
.map(text => text.trim()) // Clean whitespace
308
.filter((text, index, array) => array.indexOf(text) === index); // Remove duplicates
309
}
310
311
function processUserInput(input: unknown): string | null {
312
if (!is.string(input)) {
313
return null;
314
}
315
316
if (is.emptyStringOrWhitespace(input)) {
317
return null;
318
}
319
320
// Clean and normalize
321
return input.trim().replace(/\s+/g, ' ');
322
}
323
```
324
325
### Configuration Validation
326
327
```typescript
328
import is from '@sindresorhus/is';
329
330
interface Config {
331
apiUrl: string;
332
timeout: number;
333
retries: number;
334
debug: boolean;
335
}
336
337
function validateConfig(config: Record<string, unknown>): Config {
338
// API URL validation
339
if (!is.urlString(config.apiUrl)) {
340
throw new Error('apiUrl must be a valid URL');
341
}
342
343
// Timeout validation
344
let timeout: number;
345
if (is.numericString(config.timeout)) {
346
timeout = Number(config.timeout);
347
} else if (is.number(config.timeout)) {
348
timeout = config.timeout;
349
} else {
350
throw new Error('timeout must be a number');
351
}
352
353
// Retries validation
354
let retries: number;
355
if (is.numericString(config.retries)) {
356
retries = Number(config.retries);
357
} else if (is.number(config.retries)) {
358
retries = config.retries;
359
} else {
360
throw new Error('retries must be a number');
361
}
362
363
// Debug flag
364
let debug: boolean;
365
if (is.boolean(config.debug)) {
366
debug = config.debug;
367
} else if (is.string(config.debug)) {
368
debug = config.debug.toLowerCase() === 'true';
369
} else {
370
debug = false;
371
}
372
373
return {
374
apiUrl: config.apiUrl,
375
timeout,
376
retries,
377
debug
378
};
379
}
380
```
381
382
### Search and Filter
383
384
```typescript
385
import is from '@sindresorhus/is';
386
387
function searchItems(items: unknown[], query: unknown): string[] {
388
if (!is.nonEmptyStringAndNotWhitespace(query)) {
389
return [];
390
}
391
392
const searchTerm = query.toLowerCase();
393
394
return items
395
.filter(is.string)
396
.filter(item => item.toLowerCase().includes(searchTerm));
397
}
398
399
function filterValidUrls(urls: unknown[]): string[] {
400
return urls.filter(is.urlString);
401
}
402
```
403
404
## Notes
405
406
- Empty string checking distinguishes between `''` and whitespace-only strings
407
- `isNonEmptyString()` includes whitespace-only strings; use `isNonEmptyStringAndNotWhitespace()` to exclude them
408
- Whitespace detection includes spaces, tabs, newlines, and other whitespace characters
409
- Numeric string validation excludes `'NaN'` but includes `'Infinity'` and `'-Infinity'`
410
- URL validation uses the `URL` constructor internally for accurate validation
411
- URL validation supports all valid URL schemes (http, https, ftp, mailto, etc.)
412
- All string checks work with TypeScript type guards for compile-time type narrowing
413
- `NonEmptyString` type ensures string has at least one character at compile time