PartialDeep: Skip constructor (#730)

This commit is contained in:
Haozheng Li 2023-10-25 17:27:39 +08:00 committed by GitHub
parent 3ee234ad18
commit 75edeefd4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 14 deletions

View File

@ -59,7 +59,7 @@ const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true}> = {
@category Set
@category Map
*/
export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends BuiltIns
export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends BuiltIns | (((...arguments_: any[]) => unknown)) | (new (...arguments_: any[]) => unknown)
? T
: T extends Map<infer KeyType, infer ValueType>
? PartialMapDeep<KeyType, ValueType, Options>
@ -69,19 +69,17 @@ export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends
? PartialReadonlyMapDeep<KeyType, ValueType, Options>
: T extends ReadonlySet<infer ItemType>
? PartialReadonlySetDeep<ItemType, Options>
: T extends ((...arguments_: any[]) => unknown)
? T | undefined
: T extends object
? T extends ReadonlyArray<infer ItemType> // Test for arrays/tuples, per https://github.com/microsoft/TypeScript/issues/35156
? Options['recurseIntoArrays'] extends true
? ItemType[] extends T // Test for arrays (non-tuples) specifically
? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
? ReadonlyArray<PartialDeep<ItemType | undefined, Options>>
: Array<PartialDeep<ItemType | undefined, Options>>
: PartialObjectDeep<T, Options> // Tuples behave properly
: T // If they don't opt into array testing, just use the original type
: PartialObjectDeep<T, Options>
: unknown;
: T extends object
? T extends ReadonlyArray<infer ItemType> // Test for arrays/tuples, per https://github.com/microsoft/TypeScript/issues/35156
? Options['recurseIntoArrays'] extends true
? ItemType[] extends T // Test for arrays (non-tuples) specifically
? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
? ReadonlyArray<PartialDeep<ItemType | undefined, Options>>
: Array<PartialDeep<ItemType | undefined, Options>>
: PartialObjectDeep<T, Options> // Tuples behave properly
: T // If they don't opt into array testing, just use the original type
: PartialObjectDeep<T, Options>
: unknown;
/**
Same as `PartialDeep`, but accepts only `Map`s and as inputs. Internal helper for `PartialDeep`.

View File

@ -1,10 +1,15 @@
import {expectType, expectError, expectAssignable} from 'tsd';
import type {PartialDeep} from '../index';
class ClassA {
foo = 1;
}
const foo = {
baz: 'fred',
bar: {
function: (_: string): void => undefined,
classConstructor: ClassA,
object: {key: 'value'},
string: 'waldo',
number: 1,
@ -30,6 +35,11 @@ let partialDeepFoo: PartialDeep<typeof foo, {recurseIntoArrays: true}> = foo;
expectError(expectType<Partial<typeof foo>>(partialDeepFoo));
const partialDeepBar: PartialDeep<typeof foo.bar, {recurseIntoArrays: true}> = foo.bar;
expectType<typeof partialDeepBar | undefined>(partialDeepFoo.bar);
// Check for constructor
expectType<typeof ClassA | undefined>(partialDeepFoo.bar!.classConstructor);
const instance = new partialDeepFoo.bar!.classConstructor!();
instance.foo = 2;
const b = partialDeepFoo.bar!.constructor;
expectType<((_: string) => void) | undefined>(partialDeepFoo.bar!.function);
expectAssignable<object | undefined>(partialDeepFoo.bar!.object);
expectType<string | undefined>(partialDeepFoo.bar!.string);