Skip to content

Commit 278df80

Browse files
PicoI2som-smsindresorhus
authored
PartialDeep: Add allowUndefinedInArrays option (#1019)
Co-authored-by: Som Shekhar Mukherjee <49264891+som-sm@users.noreply.github.com> Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
1 parent a366c0f commit 278df80

File tree

2 files changed

+46
-10
lines changed

2 files changed

+46
-10
lines changed

source/partial-deep.d.ts

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {BuiltIns} from './internal';
22

33
/**
4-
@see PartialDeep
4+
@see {@link PartialDeep}
55
*/
66
export type PartialDeepOptions = {
77
/**
@@ -10,6 +10,32 @@ export type PartialDeepOptions = {
1010
@default false
1111
*/
1212
readonly recurseIntoArrays?: boolean;
13+
14+
/**
15+
Allows `undefined` values in non-tuple arrays.
16+
17+
- When set to `true`, elements of non-tuple arrays can be `undefined`.
18+
- When set to `false`, only explicitly defined elements are allowed in non-tuple arrays, ensuring stricter type checking.
19+
20+
@default true
21+
22+
@example
23+
You can prevent `undefined` values in non-tuple arrays by passing `{recurseIntoArrays: true; allowUndefinedInNonTupleArrays: false}` as the second type argument:
24+
25+
```
26+
import type {PartialDeep} from 'type-fest';
27+
28+
type Settings = {
29+
languages: string[];
30+
};
31+
32+
declare const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true; allowUndefinedInNonTupleArrays: false}>;
33+
34+
partialSettings.languages = [undefined]; // Error
35+
partialSettings.languages = []; // Ok
36+
```
37+
*/
38+
readonly allowUndefinedInNonTupleArrays?: boolean;
1339
};
1440

1541
/**
@@ -25,12 +51,12 @@ import type {PartialDeep} from 'type-fest';
2551
2652
const settings: Settings = {
2753
textEditor: {
28-
fontSize: 14;
29-
fontColor: '#000000';
30-
fontWeight: 400;
31-
}
32-
autocomplete: false;
33-
autosave: true;
54+
fontSize: 14,
55+
fontColor: '#000000',
56+
fontWeight: 400
57+
},
58+
autocomplete: false,
59+
autosave: true
3460
};
3561
3662
const applySavedSettings = (savedSettings: PartialDeep<Settings>) => {
@@ -45,7 +71,7 @@ By default, this does not affect elements in array and tuple types. You can chan
4571
```
4672
import type {PartialDeep} from 'type-fest';
4773
48-
interface Settings {
74+
type Settings = {
4975
languages: string[];
5076
}
5177
@@ -54,6 +80,8 @@ const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true}> = {
5480
};
5581
```
5682
83+
@see {@link PartialDeepOptions}
84+
5785
@category Object
5886
@category Array
5987
@category Set
@@ -74,8 +102,8 @@ export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends
74102
? Options['recurseIntoArrays'] extends true
75103
? ItemType[] extends T // Test for arrays (non-tuples) specifically
76104
? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
77-
? ReadonlyArray<PartialDeep<ItemType | undefined, Options>>
78-
: Array<PartialDeep<ItemType | undefined, Options>>
105+
? ReadonlyArray<PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
106+
: Array<PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
79107
: PartialObjectDeep<T, Options> // Tuples behave properly
80108
: T // If they don't opt into array testing, just use the original type
81109
: PartialObjectDeep<T, Options>

test-d/partial-deep.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ expectAssignable<PartialDeep<RecurseObject>>(recurseObject);
7979
const partialDeepNoRecurseIntoArraysFoo: PartialDeep<typeof foo> = foo;
8080
// Check that `{recurseIntoArrays: true}` behaves as intended
8181
expectType<PartialDeep<typeof foo, {recurseIntoArrays: true}>>(partialDeepFoo);
82+
83+
// Check that `{allowUndefinedInNonTupleArrays: true}` is the default
84+
const partialDeepAllowUndefinedInNonTupleArraysFoo: PartialDeep<typeof foo, {recurseIntoArrays: true}> = foo;
85+
expectType<Array<string | undefined> | undefined>(partialDeepAllowUndefinedInNonTupleArraysFoo.bar!.array);
86+
// Check that `{allowUndefinedInNonTupleArrays: false}` behaves as intended
87+
const partialDeepDoNotAllowUndefinedInNonTupleArraysFoo: PartialDeep<typeof foo, {recurseIntoArrays: true; allowUndefinedInNonTupleArrays: false}> = foo;
88+
expectType<string[] | undefined>(partialDeepDoNotAllowUndefinedInNonTupleArraysFoo.bar!.array);
89+
8290
// These are mostly the same checks as before, but the array/tuple types are different.
8391
// @ts-expect-error
8492
expectType<Partial<typeof foo>>(partialDeepNoRecurseIntoArraysFoo);

0 commit comments

Comments
 (0)