Skip to content

Commit fbccaab

Browse files
authored
StringRepeat: Add support for generating longer strings & fix instantiations with unions (#1046)
1 parent 4789c7c commit fbccaab

File tree

2 files changed

+34
-12
lines changed

2 files changed

+34
-12
lines changed

source/string-repeat.d.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import type {IsNumericLiteral} from './is-literal';
12
import type {IsNegative} from './numeric';
2-
import type {Subtract} from './subtract';
33

44
/**
55
Returns a new string which contains the specified number of copies of a given string, just like `String#repeat()`.
@@ -28,16 +28,20 @@ stringRepeat('=', 3);
2828
export type StringRepeat<
2929
Input extends string,
3030
Count extends number,
31-
> = number extends Count
32-
? Input extends ''
33-
? ''
34-
: string
35-
: IsNegative<Count> extends true
31+
> = StringRepeatHelper<Input, Count>;
32+
33+
type StringRepeatHelper<
34+
Input extends string,
35+
Count extends number,
36+
Counter extends never[] = [],
37+
Accumulator extends string = '',
38+
> =
39+
IsNegative<Count> extends true
3640
? never
37-
: Count extends 0
41+
: Input extends ''
3842
? ''
39-
: string extends Input
40-
? string
41-
: StringRepeat<Input, Subtract<Count, 1>> extends infer R extends string
42-
? `${Input}${R}`
43-
: never;
43+
: Count extends Counter['length']
44+
? Accumulator
45+
: IsNumericLiteral<Count> extends false
46+
? string
47+
: StringRepeatHelper<Input, Count, [...Counter, never], `${Accumulator}${Input}`>;

test-d/string-repeat.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,21 @@ expectType<StringRepeat<'0', 5>>('00000');
1717
expectType<StringRepeat<'012345-', 0>>('');
1818
expectType<StringRepeat<'012345-', 1>>('012345-');
1919
expectType<StringRepeat<'012345-', 5>>('012345-012345-012345-012345-012345-');
20+
21+
// Non literal strings
22+
expectType<StringRepeat<string, 2>>(unknown as string);
23+
expectType<StringRepeat<`abc${string}`, 2>>(unknown as `abc${string}abc${string}`);
24+
expectType<StringRepeat<Uppercase<string>, 2>>(unknown as `${Uppercase<string>}${Uppercase<string>}`);
25+
26+
// Union cases
27+
expectType<StringRepeat<'0' | '1', 5>>(unknown as '00000' | '11111');
28+
expectType<StringRepeat<'0', 4 | 5>>(unknown as '0000' | '00000');
29+
expectType<StringRepeat<'0' | '1', 4 | 5>>(unknown as '0000' | '00000' | '1111' | '11111');
30+
31+
// Recursion depth at which a non-tail recursive implementation starts to fail.
32+
const fiftyZeroes = '00000000000000000000000000000000000000000000000000';
33+
expectType<StringRepeat<'0', 50>>(fiftyZeroes);
34+
35+
// Maximum allowed recursion depth for a tail recursive implementation.
36+
const nineHundredNinetyNineZeroes = '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000';
37+
expectType<StringRepeat<'0', 999>>(nineHundredNinetyNineZeroes);

0 commit comments

Comments
 (0)