From a00161176357a5c66a1fa16f12f1417e72b58720 Mon Sep 17 00:00:00 2001 From: Olzhas Alexandrov Date: Fri, 10 Sep 2021 09:43:51 +0600 Subject: [PATCH] Support numbers in `Join` type (#258) --- readme.md | 2 +- source/join.d.ts | 17 ++++++++++++----- test-d/join.ts | 14 +++++++++----- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/readme.md b/readme.md index 5ea80587b..311e6b675 100644 --- a/readme.md +++ b/readme.md @@ -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. diff --git a/source/join.d.ts b/source/join.d.ts index cab0ec0b3..3b264b8d0 100644 --- a/source/join.d.ts +++ b/source/join.d.ts @@ -1,5 +1,5 @@ /** -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. @@ -7,16 +7,23 @@ Use-case: Defining key paths in a nested object. For example, for dot-notation f ``` 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, 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}` : - string; + Strings extends [string | number, ...infer Rest] ? `${Strings[0]}${Delimiter}${Join}` : + string | number; diff --git a/test-d/join.ts b/test-d/join.ts index 5959c2a41..e7474c618 100644 --- a/test-d/join.ts +++ b/test-d/join.ts @@ -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';