Skip to content

Commit b34b1d8

Browse files
authored
ArrayTail: Enable preserveReadonly option by default and remove the option (#1173)
1 parent c5392da commit b34b1d8

File tree

3 files changed

+32
-70
lines changed

3 files changed

+32
-70
lines changed

source/array-tail.d.ts

Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,7 @@
11
import type {If} from './if.d.ts';
2-
import type {ApplyDefaultOptions, IsArrayReadonly} from './internal/index.d.ts';
2+
import type {IsArrayReadonly} from './internal/index.d.ts';
33
import type {UnknownArray} from './unknown-array.d.ts';
44

5-
/**
6-
@see {@link ArrayTail}
7-
*/
8-
type ArrayTailOptions = {
9-
/**
10-
Return a readonly array if the input array is readonly.
11-
12-
@default false
13-
14-
@example
15-
```
16-
import type {ArrayTail} from 'type-fest';
17-
18-
type Example1 = ArrayTail<readonly [string, number, boolean], {preserveReadonly: true}>;
19-
//=> readonly [number, boolean]
20-
21-
type Example2 = ArrayTail<[string, number, boolean], {preserveReadonly: true}>;
22-
//=> [number, boolean]
23-
24-
type Example3 = ArrayTail<readonly [string, number, boolean], {preserveReadonly: false}>;
25-
//=> [number, boolean]
26-
27-
type Example4 = ArrayTail<[string, number, boolean], {preserveReadonly: false}>;
28-
//=> [number, boolean]
29-
```
30-
*/
31-
preserveReadonly?: boolean;
32-
};
33-
34-
type DefaultArrayTailOptions = {
35-
preserveReadonly: false;
36-
};
37-
385
/**
396
Extracts the type of an array or tuple minus the first element.
407
@@ -55,18 +22,12 @@ add3(4);
5522
//=> 7
5623
```
5724
58-
@see {@link ArrayTailOptions}
59-
6025
@category Array
6126
*/
62-
export type ArrayTail<TArray extends UnknownArray, Options extends ArrayTailOptions = {}> =
63-
ApplyDefaultOptions<ArrayTailOptions, DefaultArrayTailOptions, Options> extends infer ResolvedOptions extends Required<ArrayTailOptions>
64-
? TArray extends UnknownArray // For distributing `TArray`
65-
? _ArrayTail<TArray> extends infer Result
66-
? ResolvedOptions['preserveReadonly'] extends true
67-
? If<IsArrayReadonly<TArray>, Readonly<Result>, Result>
68-
: Result
69-
: never // Should never happen
27+
export type ArrayTail<TArray extends UnknownArray> =
28+
TArray extends UnknownArray // For distributing `TArray`
29+
? _ArrayTail<TArray> extends infer Result
30+
? If<IsArrayReadonly<TArray>, Readonly<Result>, Result>
7031
: never // Should never happen
7132
: never; // Should never happen
7233

source/merge-deep.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ type OmitRestTypeHelper<
8686
Tail extends UnknownArrayOrTuple,
8787
Type extends UnknownArrayOrTuple,
8888
Result extends UnknownArrayOrTuple = [],
89-
> = Tail extends []
89+
> = Tail extends readonly []
9090
? Result
9191
: OmitRestType<Tail, [...Result, FirstArrayElement<Type>]>;
9292

test-d/array-tail.ts

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,49 @@
11
import {expectType} from 'tsd';
2-
import type {ArrayTail, UnknownArray} from '../index.d.ts';
2+
import type {ArrayTail} from '../index.d.ts';
33

44
declare const getArrayTail: <T extends readonly unknown[]>(array: T) => ArrayTail<T>;
55

6-
expectType<[]>(getArrayTail([]));
7-
expectType<[]>(getArrayTail(['a']));
8-
expectType<[]>(getArrayTail(['a', 'b', 'c']));
6+
expectType<[]>(getArrayTail([] as []));
7+
expectType<[]>(getArrayTail(['a'] as ['a']));
8+
expectType<['b', 'c']>(getArrayTail(['a', 'b', 'c'] as ['a', 'b', 'c']));
99

10-
expectType<[]>(getArrayTail([] as const));
11-
expectType<[]>(getArrayTail(['a'] as const));
12-
expectType<['b', 'c']>(getArrayTail(['a', 'b', 'c'] as const));
10+
expectType<readonly []>(getArrayTail([] as const));
11+
expectType<readonly []>(getArrayTail(['a'] as const));
12+
expectType<readonly ['b', 'c']>(getArrayTail(['a', 'b', 'c'] as const));
1313

1414
// Optional elements tests
15-
expectType<[undefined, 'c']>(getArrayTail(['a', undefined, 'c'] as const));
15+
expectType<readonly [undefined, 'c']>(getArrayTail(['a', undefined, 'c'] as const));
1616

1717
// Mixed optional/required
1818
type MixedArray = [string, undefined?, number?];
1919
expectType<[undefined?, number?]>(getArrayTail(['hello'] as MixedArray));
2020

2121
// Optional numbers
22-
expectType<[undefined, 3]>(getArrayTail([1, undefined, 3] as const));
22+
expectType<readonly [undefined, 3]>(getArrayTail([1, undefined, 3] as const));
2323

2424
// Complex mixed case
2525
type ComplexArray = [string, boolean, number?, string?];
2626
expectType<[boolean, number?, string?]>(getArrayTail(['test', false] as ComplexArray));
2727

2828
// All optional elements
2929
expectType<['b'?]>([] as ArrayTail<['a'?, 'b'?]>);
30+
expectType<readonly [number?]>({} as ArrayTail<readonly [string?, number?]>);
31+
32+
// Rest element
33+
expectType<readonly [number, boolean, ...string[]]>({} as ArrayTail<readonly [string, number, boolean, ...string[]]>); // Required & Rest
34+
expectType<readonly [number?, boolean?, ...string[]]>({} as ArrayTail<readonly [string?, number?, boolean?, ...string[]]>); // Optional & Rest
35+
expectType<readonly [number, boolean?, ...string[]]>({} as ArrayTail<readonly [string, number, boolean?, ...string[]]>); // Required, Optional & Rest
36+
// expectType<readonly [...string[], string, number]>({} as ArrayTail<readonly [...string[], string, number]>); // Rest & Required
37+
expectType<readonly [number, ...string[], boolean, bigint]>({} as ArrayTail<readonly [string, number, ...string[], boolean, bigint]>); // Required, Rest & Required
3038

3139
// Union of tuples
3240
expectType<[] | ['b']>([] as ArrayTail<[] | ['a', 'b']>);
33-
expectType<['y'?] | ['b', ...string[]] | []>([] as ArrayTail<readonly ['x'?, 'y'?] | ['a', 'b', ...string[]] | readonly string[]>);
34-
35-
// `preserveReadonly` option
36-
type ReadonlyPreservingArrayTail<Type extends UnknownArray> = ArrayTail<Type, {preserveReadonly: true}>;
37-
38-
expectType<[]>({} as ReadonlyPreservingArrayTail<[]>);
39-
expectType<readonly []>({} as ReadonlyPreservingArrayTail<readonly []>);
40-
expectType<[number?, ...string[]]>({} as ReadonlyPreservingArrayTail<[string?, number?, ...string[]]>);
41-
expectType<readonly [number?, ...string[]]>({} as ReadonlyPreservingArrayTail<readonly [string?, number?, ...string[]]>);
42-
43-
expectType<[number] | readonly [boolean, string?]>({} as ReadonlyPreservingArrayTail<[string, number] | readonly [number, boolean, string?]>);
44-
expectType<readonly [number] | readonly []>({} as ReadonlyPreservingArrayTail<readonly [string, number] | readonly string[]>);
45-
expectType<[number?] | [boolean, string?] | []>({} as ReadonlyPreservingArrayTail<[string?, number?] | [number, boolean, string?] | [...string[], number]>);
46-
47-
expectType<[]>({} as ReadonlyPreservingArrayTail<string[]>);
48-
expectType<readonly []>({} as ReadonlyPreservingArrayTail<readonly string[]>);
41+
expectType<readonly ['y'?] | ['b', ...string[]] | readonly []>([] as ArrayTail<readonly ['x'?, 'y'?] | ['a', 'b', ...string[]] | readonly string[]>);
42+
expectType<[number] | readonly [boolean, string?]>({} as ArrayTail<[string, number] | readonly [number, boolean, string?]>);
43+
expectType<readonly [number] | readonly []>({} as ArrayTail<readonly [string, number] | readonly string[]>);
44+
45+
// Non tuple arrays
46+
expectType<[]>({} as ArrayTail<string[]>);
47+
expectType<readonly []>({} as ArrayTail<readonly string[]>);
48+
expectType<[]>({} as ArrayTail<never[]>);
49+
expectType<[]>({} as ArrayTail<any[]>);

0 commit comments

Comments
 (0)