0
# String & Type Functions
1
2
Ramda provides 13 essential functions for string manipulation and type checking. This includes 8 string functions for text processing and 5 type functions for runtime type validation and inspection.
3
4
## String Functions
5
6
### Case Conversion
7
8
```javascript { .api }
9
// Convert to uppercase
10
R.toUpper('hello world'); // => 'HELLO WORLD'
11
R.toUpper('MiXeD cAsE'); // => 'MIXED CASE'
12
13
// Convert to lowercase
14
R.toLower('HELLO WORLD'); // => 'hello world'
15
R.toLower('MiXeD cAsE'); // => 'mixed case'
16
17
// Curried usage for transformations
18
const normalizeNames = R.map(R.pipe(
19
R.trim,
20
R.toLower,
21
R.replace(/\s+/g, ' ') // Normalize whitespace
22
));
23
24
normalizeNames([' ALICE ', 'bob', ' CAROL SMITH ']);
25
// => ['alice', 'bob', 'carol smith']
26
27
// Case-insensitive operations
28
const caseInsensitiveIncludes = R.pipe(
29
R.juxt([R.toLower, R.pipe(R.nthArg(1), R.toLower)]),
30
R.apply(R.includes)
31
);
32
33
const containsWord = R.curry((word, text) =>
34
R.pipe(R.toLower, R.includes(R.toLower(word)))(text)
35
);
36
37
containsWord('HELLO', 'hello world'); // => true
38
```
39
40
### String Trimming
41
42
```javascript { .api }
43
// Remove whitespace from both ends
44
R.trim(' hello world '); // => 'hello world'
45
R.trim('\n\t text \n\t'); // => 'text'
46
R.trim('no-spaces'); // => 'no-spaces'
47
48
// Clean up user input
49
const sanitizeInput = R.pipe(
50
R.trim,
51
R.replace(/\s+/g, ' '), // Replace multiple spaces with single space
52
R.when(R.isEmpty, R.always('(empty)'))
53
);
54
55
sanitizeInput(' hello world '); // => 'hello world'
56
sanitizeInput(' '); // => '(empty)'
57
58
// Process form data
59
const cleanFormData = R.map(R.when(R.is(String), R.trim));
60
const formData = {
61
name: ' John Doe ',
62
email: ' john@example.com ',
63
age: 30
64
};
65
66
cleanFormData(formData);
67
// => { name: 'John Doe', email: 'john@example.com', age: 30 }
68
```
69
70
### String Splitting and Joining
71
72
```javascript { .api }
73
// Split string by separator
74
R.split(' ', 'hello world foo'); // => ['hello', 'world', 'foo']
75
R.split(',', 'a,b,c,d'); // => ['a', 'b', 'c', 'd']
76
R.split('', 'hello'); // => ['h', 'e', 'l', 'l', 'o']
77
78
// Split by regex
79
R.split(/\s+/, 'hello world\ttest'); // => ['hello', 'world', 'test']
80
R.split(/[,;]/, 'a,b;c,d'); // => ['a', 'b', 'c', 'd']
81
82
// Parse CSV-like data
83
const parseCSVRow = R.pipe(
84
R.split(','),
85
R.map(R.trim),
86
R.reject(R.isEmpty)
87
);
88
89
parseCSVRow('name, age, city, '); // => ['name', 'age', 'city']
90
91
// Path manipulation
92
const getPathSegments = R.pipe(
93
R.split('/'),
94
R.reject(R.isEmpty)
95
);
96
97
getPathSegments('/users/123/profile'); // => ['users', '123', 'profile']
98
99
// Word processing
100
const getWords = R.pipe(
101
R.toLower,
102
R.split(/\W+/),
103
R.reject(R.isEmpty)
104
);
105
106
getWords('Hello, World! How are you?'); // => ['hello', 'world', 'how', 'are', 'you']
107
```
108
109
### String Replacement
110
111
```javascript { .api }
112
// Replace substring or pattern
113
R.replace('foo', 'bar', 'foo foo foo'); // => 'bar foo foo' (first occurrence)
114
R.replace(/foo/g, 'bar', 'foo foo foo'); // => 'bar bar bar' (all occurrences)
115
116
// Template replacement
117
const template = 'Hello, {name}! Welcome to {site}.';
118
const replacePlaceholder = R.curry((key, value) =>
119
R.replace(new RegExp(`\\{${key}\\}`, 'g'), value)
120
);
121
122
const personalizeMessage = R.pipe(
123
replacePlaceholder('name', 'Alice'),
124
replacePlaceholder('site', 'Our Platform')
125
);
126
127
personalizeMessage(template); // => 'Hello, Alice! Welcome to Our Platform.'
128
129
// URL slug generation
130
const createSlug = R.pipe(
131
R.toLower,
132
R.trim,
133
R.replace(/[^\w\s-]/g, ''), // Remove special chars
134
R.replace(/\s+/g, '-'), // Replace spaces with hyphens
135
R.replace(/-+/g, '-'), // Replace multiple hyphens with single
136
R.replace(/^-|-$/g, '') // Remove leading/trailing hyphens
137
);
138
139
createSlug(' Hello, World! This is a Test '); // => 'hello-world-this-is-a-test'
140
141
// Clean phone numbers
142
const cleanPhone = R.pipe(
143
R.replace(/\D/g, ''), // Remove non-digits
144
R.replace(/^1/, ''), // Remove country code
145
R.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3') // Format
146
);
147
148
cleanPhone('1-555-123-4567'); // => '(555) 123-4567'
149
```
150
151
### Pattern Matching
152
153
```javascript { .api }
154
// Test if string matches pattern
155
R.test(/^\d+$/, '12345'); // => true (all digits)
156
R.test(/^\d+$/, '123a5'); // => false
157
R.test(/^[a-z]+$/i, 'Hello'); // => true (letters only, case-insensitive)
158
159
// Extract matches from string
160
R.match(/\d+/g, 'abc 123 def 456'); // => ['123', '456']
161
R.match(/(\w+)@(\w+)/, 'user@domain.com'); // => ['user@domain', 'user', 'domain']
162
R.match(/xyz/, 'abc'); // => [] (no matches)
163
164
// Validation functions
165
const isEmail = R.test(/^[\w\.-]+@[\w\.-]+\.\w+$/);
166
const isPhone = R.test(/^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/);
167
const isZipCode = R.test(/^\d{5}(-\d{4})?$/);
168
169
isEmail('user@example.com'); // => true
170
isPhone('(555) 123-4567'); // => true
171
isZipCode('12345-6789'); // => true
172
173
// Extract information
174
const extractDomain = R.pipe(
175
R.match(/@([\w.-]+)/),
176
R.nth(1),
177
R.defaultTo('unknown')
178
);
179
180
extractDomain('user@example.com'); // => 'example.com'
181
extractDomain('invalid-email'); // => 'unknown'
182
183
// Parse structured data
184
const parseLogEntry = R.pipe(
185
R.match(/(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) \[(\w+)\] (.+)/),
186
R.ifElse(
187
R.isEmpty,
188
R.always(null),
189
([, date, time, level, message]) => ({ date, time, level, message })
190
)
191
);
192
193
parseLogEntry('2023-01-15 14:30:45 [ERROR] Database connection failed');
194
// => { date: '2023-01-15', time: '14:30:45', level: 'ERROR', message: 'Database connection failed' }
195
```
196
197
### String Conversion and Representation
198
199
```javascript { .api }
200
// Convert any value to string representation
201
R.toString(42); // => '42'
202
R.toString([1, 2, 3]); // => '[1, 2, 3]'
203
R.toString({a: 1, b: 2}); // => '{"a": 1, "b": 2}'
204
R.toString(new Date('2023-01-15')); // => 'new Date("2023-01-15T00:00:00.000Z")'
205
R.toString(null); // => 'null'
206
R.toString(undefined); // => 'undefined'
207
208
// Safe string conversion for display
209
const displayValue = R.pipe(
210
R.when(R.isNil, R.always('N/A')),
211
R.toString
212
);
213
214
displayValue(42); // => '42'
215
displayValue(null); // => 'N/A'
216
displayValue({id: 123}); // => '{"id": 123}'
217
218
// Format objects for logging
219
const formatForLog = R.pipe(
220
R.toString,
221
R.replace(/"/g, ''), // Remove quotes for cleaner output
222
R.replace(/,/g, ', ') // Add spacing after commas
223
);
224
225
formatForLog({user: 'alice', action: 'login'});
226
// => '{user: alice, action: login}'
227
```
228
229
## Type Functions
230
231
### Type Detection
232
233
```javascript { .api }
234
// Get type name as string
235
R.type(42); // => 'Number'
236
R.type('hello'); // => 'String'
237
R.type([1, 2, 3]); // => 'Array'
238
R.type({a: 1}); // => 'Object'
239
R.type(null); // => 'Null'
240
R.type(undefined); // => 'Undefined'
241
R.type(true); // => 'Boolean'
242
R.type(/regex/); // => 'RegExp'
243
R.type(() => {}); // => 'Function'
244
R.type(async () => {}); // => 'AsyncFunction'
245
R.type(new Date()); // => 'Date'
246
247
// Type-based processing
248
const processValue = R.cond([
249
[R.pipe(R.type, R.equals('Number')), R.multiply(2)],
250
[R.pipe(R.type, R.equals('String')), R.toUpper],
251
[R.pipe(R.type, R.equals('Array')), R.length],
252
[R.T, R.always('Unknown type')]
253
]);
254
255
processValue(5); // => 10
256
processValue('hello'); // => 'HELLO'
257
processValue([1, 2, 3]); // => 3
258
processValue(true); // => 'Unknown type'
259
```
260
261
### Instance and Constructor Checking
262
263
```javascript { .api }
264
// Check if value is instance of constructor
265
R.is(Number, 42); // => true
266
R.is(String, 'hello'); // => true
267
R.is(Array, [1, 2, 3]); // => true
268
R.is(Object, {}); // => true
269
R.is(Date, new Date()); // => true
270
R.is(RegExp, /pattern/); // => true
271
272
// Check inheritance chain
273
R.is(Object, []); // => true (arrays inherit from Object)
274
R.is(Object, 'string'); // => false (primitives don't inherit)
275
276
// Custom constructor checking
277
function Person(name) { this.name = name; }
278
const john = new Person('John');
279
280
R.is(Person, john); // => true
281
R.is(Object, john); // => true
282
283
// Type guards for data validation
284
const isValidUser = R.where({
285
id: R.is(Number),
286
name: R.is(String),
287
email: R.is(String),
288
active: R.is(Boolean)
289
});
290
291
const user = { id: 123, name: 'Alice', email: 'alice@example.com', active: true };
292
isValidUser(user); // => true
293
```
294
295
### Null and Undefined Checking
296
297
```javascript { .api }
298
// Check for null or undefined
299
R.isNil(null); // => true
300
R.isNil(undefined); // => true
301
R.isNil(0); // => false
302
R.isNil(false); // => false
303
R.isNil(''); // => false
304
R.isNil([]); // => false
305
306
// Check for non-null and non-undefined
307
R.isNotNil(null); // => false
308
R.isNotNil(undefined); // => false
309
R.isNotNil(0); // => true
310
R.isNotNil(false); // => true
311
R.isNotNil(''); // => true
312
313
// Safe property access
314
const safeProp = R.curry((key, obj) =>
315
R.when(R.isNotNil, R.prop(key))(obj)
316
);
317
318
safeProp('name', {name: 'Alice'}); // => 'Alice'
319
safeProp('name', null); // => null
320
safeProp('name', undefined); // => undefined
321
322
// Filter out null/undefined values
323
const removeNils = R.filter(R.isNotNil);
324
removeNils([1, null, 2, undefined, 3]); // => [1, 2, 3]
325
326
// Provide defaults for nil values
327
const withDefaults = R.pipe(
328
R.when(R.isNil, R.always({})),
329
R.merge({name: 'Anonymous', age: 0})
330
);
331
332
withDefaults({name: 'Alice'}); // => {name: 'Alice', age: 0}
333
withDefaults(null); // => {name: 'Anonymous', age: 0}
334
```
335
336
### Property Type Checking
337
338
```javascript { .api }
339
// Check type of object property
340
R.propIs(Number, 'age', {age: 30}); // => true
341
R.propIs(String, 'name', {name: 'Alice'}); // => true
342
R.propIs(Array, 'tags', {tags: ['a', 'b']}); // => true
343
R.propIs(Number, 'missing', {}); // => false
344
345
// Validate object structure
346
const validateProduct = R.where({
347
id: R.propIs(Number, 'id'),
348
name: R.propIs(String, 'name'),
349
price: R.propIs(Number, 'price'),
350
tags: R.propIs(Array, 'tags')
351
});
352
353
const product = {
354
id: 123,
355
name: 'Widget',
356
price: 29.99,
357
tags: ['electronics', 'gadget']
358
};
359
360
validateProduct(product); // => true
361
362
// Type-safe property extraction
363
const getNumberProp = R.curry((key, obj) =>
364
R.when(R.propIs(Number, key), R.prop(key))(obj)
365
);
366
367
getNumberProp('age', {age: 30}); // => 30
368
getNumberProp('age', {age: 'thirty'}); // => {age: 'thirty'} (unchanged)
369
```
370
371
### Advanced Type Operations
372
373
```javascript { .api }
374
// Runtime type checking with detailed info
375
const analyzeValue = R.applySpec({
376
value: R.identity,
377
type: R.type,
378
isNil: R.isNil,
379
isNumber: R.is(Number),
380
isString: R.is(String),
381
isArray: R.is(Array),
382
isEmpty: R.isEmpty
383
});
384
385
analyzeValue('hello');
386
// => {
387
// value: 'hello',
388
// type: 'String',
389
// isNil: false,
390
// isNumber: false,
391
// isString: true,
392
// isArray: false,
393
// isEmpty: false
394
// }
395
396
// Type-based routing
397
const routeByType = R.cond([
398
[R.is(String), R.pipe(R.toUpper, R.concat('STRING: '))],
399
[R.is(Number), R.pipe(R.multiply(2), R.toString, R.concat('NUMBER: '))],
400
[R.is(Array), R.pipe(R.length, R.toString, R.concat('ARRAY LENGTH: '))],
401
[R.T, R.pipe(R.type, R.concat('UNKNOWN TYPE: '))]
402
]);
403
404
routeByType('hello'); // => 'STRING: HELLO'
405
routeByType(42); // => 'NUMBER: 84'
406
routeByType([1, 2, 3]); // => 'ARRAY LENGTH: 3'
407
routeByType(true); // => 'UNKNOWN TYPE: Boolean'
408
```
409
410
These string and type functions provide essential utilities for text processing, data validation, and runtime type safety in functional JavaScript applications.