Skip to content

Commit

Permalink
Support numbers in Join type (#258)
Browse files Browse the repository at this point in the history
  • Loading branch information
o-alexandrov committed Sep 10, 2021
1 parent 28199b0 commit a001611
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 11 deletions.
2 changes: 1 addition & 1 deletion readme.md
Expand Up @@ -144,7 +144,7 @@ Click the type names for complete docs.
- [`DelimiterCase`](source/delimiter-case.d.ts) – Convert a string literal to a custom string delimiter casing.
- [`DelimiterCasedProperties`](source/delimiter-cased-properties.d.ts) – Convert object properties to a custom string delimiter casing.
- [`DelimiterCasedPropertiesDeep`](source/delimiter-cased-properties-deep.d.ts) – Convert object properties to a custom string delimiter casing recursively.
- [`Join`](source/join.d.ts) - Join an array of strings using the given string as delimiter.
- [`Join`](source/join.d.ts) - Join an array of strings and/or numbers using the given string as a delimiter.
- [`Split`](source/split.d.ts) - Represents an array of strings split using a given character or character set.
- [`Trim`](source/trim.d.ts) - Remove leading and trailing spaces from a string.
- [`Get`](source/get.d.ts) - Get a deeply-nested property from an object using a key path, like [Lodash's `.get()`](https://lodash.com/docs/latest#get) function.
Expand Down
17 changes: 12 additions & 5 deletions source/join.d.ts
@@ -1,22 +1,29 @@
/**
Join an array of strings using the given string as delimiter.
Join an array of strings and/or numbers using the given string as a delimiter.
Use-case: Defining key paths in a nested object. For example, for dot-notation fields in MongoDB queries.
@example
```
import {Join} from 'type-fest';
// Mixed (strings & numbers) items; result is: 'foo.0.baz'
const path: Join<['foo', 0, 'baz'], '.'> = ['foo', 0, 'baz'].join('.');
// Only string items; result is: 'foo.bar.baz'
const path: Join<['foo', 'bar', 'baz'], '.'> = ['foo', 'bar', 'baz'].join('.');
// Only number items; result is: '1.2.3'
const path: Join<[1, 2, 3], '.'> = [1, 2, 3].join('.');
```
@category Template Literals
*/
export type Join<
Strings extends string[],
Strings extends Array<string | number>,
Delimiter extends string,
> = Strings extends [] ? '' :
Strings extends [string] ? `${Strings[0]}` :
Strings extends [string | number] ? `${Strings[0]}` :
// @ts-expect-error `Rest` is inferred as `unknown` here: https://github.com/microsoft/TypeScript/issues/45281
Strings extends [string, ...infer Rest] ? `${Strings[0]}${Delimiter}${Join<Rest, Delimiter>}` :
string;
Strings extends [string | number, ...infer Rest] ? `${Strings[0]}${Delimiter}${Join<Rest, Delimiter>}` :
string | number;
14 changes: 9 additions & 5 deletions test-d/join.ts
Expand Up @@ -2,11 +2,15 @@ import {expectError, expectType} from 'tsd';
import {Join} from '../index';

// General use.
const generalTest: Join<['foo', 'bar', 'baz'], '.'> = 'foo.bar.baz';
expectType<'foo.bar.baz'>(generalTest);
expectError<'foo'>(generalTest);
expectError<'foo.bar'>(generalTest);
expectError<'foo.bar.ham'>(generalTest);
const generalTestVariantMixed: Join<['foo', 0, 'baz'], '.'> = 'foo.0.baz';
const generalTestVariantOnlyStrings: Join<['foo', 'bar', 'baz'], '.'> = 'foo.bar.baz';
const generalTestVariantOnlyNumbers: Join<[1, 2, 3], '.'> = '1.2.3';
expectType<'foo.0.baz'>(generalTestVariantMixed);
expectType<'1.2.3'>(generalTestVariantOnlyNumbers);
expectType<'foo.bar.baz'>(generalTestVariantOnlyStrings);
expectError<'foo'>(generalTestVariantOnlyStrings);
expectError<'foo.bar'>(generalTestVariantOnlyStrings);
expectError<'foo.bar.ham'>(generalTestVariantOnlyStrings);

// Empty string delimiter.
const emptyDelimiter: Join<['foo', 'bar', 'baz'], ''> = 'foobarbaz';
Expand Down

0 comments on commit a001611

Please sign in to comment.