Skip to content

Commit

Permalink
ConditionalPickDeep: Ensure it doesn't recurse into prototype prope…
Browse files Browse the repository at this point in the history
…rties (#736)
  • Loading branch information
Emiyaaaaa committed Oct 30, 2023
1 parent b9723d4 commit 9960ba4
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 23 deletions.
6 changes: 4 additions & 2 deletions source/conditional-pick-deep.d.ts
@@ -1,6 +1,8 @@
import type {IsEqual} from './is-equal';
import type {ConditionalExcept} from './conditional-except';
import type {ConditionalSimplifyDeep} from './conditional-simplify';
import type {UnknownRecord} from './unknown-record';
import type {EmptyObject} from './empty-object';

/**
Used to mark properties that should be excluded.
Expand Down Expand Up @@ -95,7 +97,7 @@ export type ConditionalPickDeep<
> = ConditionalSimplifyDeep<ConditionalExcept<{
[Key in keyof Type]: AssertCondition<Type[Key], Condition, Options> extends true
? Type[Key]
: Type[Key] extends object
: Type[Key] extends UnknownRecord
? ConditionalPickDeep<Type[Key], Condition, Options>
: typeof conditionalPickDeepSymbol;
}, (typeof conditionalPickDeepSymbol | undefined) | Record<PropertyKey, never>>>;
}, (typeof conditionalPickDeepSymbol | undefined) | EmptyObject>, never, UnknownRecord>;
109 changes: 88 additions & 21 deletions test-d/conditional-pick-deep.ts
@@ -1,46 +1,113 @@
import {expectType} from 'tsd';
import type {ConditionalPickDeep} from '../index';

declare class ClassA {
public a: string;
}

type Example = {
a: string;
b: string | boolean;
c: {
d: string;
e: {
f?: string;
g?: boolean;
h: string | boolean;
i: boolean | bigint;
optional?: boolean;
literal: 'foo';
string: string;
map: Map<string, string>;
set: Set<string>;
date: Date;
array: string[];
tuples: ['foo', 'bar'];
instanceA: ClassA;
ClassA: typeof ClassA;
function: (...args: string[]) => string;
stringOrBoolean: string | boolean;
object: {
string: string;
subObject: {
optional?: string;
string: string;
};
j: boolean;
};
};

declare const stringPick: ConditionalPickDeep<Example, string>;
expectType<{a: string; c: {d: string}}>(stringPick);
expectType<{
literal: 'foo';
string: string;
object: {
string: string;
subObject: {
string: string;
};
};
}>(stringPick);

declare const stringEqualityPick: ConditionalPickDeep<Example, string, {condition: 'equality'}>;
expectType<{
string: string;
object: {
string: string;
subObject: {
string: string;
};
};
}>(stringEqualityPick);

declare const stringPickOptional: ConditionalPickDeep<Example, string | undefined>;
expectType<{a: string; c: {d: string; e: {f?: string}}}>(stringPickOptional);
expectType<{
literal: 'foo';
string: string;
object: {
string: string;
subObject: {
optional?: string | undefined;
string: string;
};
};
}>(stringPickOptional);

declare const stringPickOptionalOnly: ConditionalPickDeep<Example, string | undefined, {condition: 'equality'}>;
expectType<{c: {e: {f?: string}}}>(stringPickOptionalOnly);
expectType<{object: {subObject: {optional?: string | undefined}}}>(stringPickOptionalOnly);

declare const booleanPick: ConditionalPickDeep<Example, boolean | undefined>;
expectType<{c: {e: {g?: boolean}; j: boolean}}>(booleanPick);
expectType<{optional?: boolean | undefined}>(booleanPick);

declare const numberPick: ConditionalPickDeep<Example, number>;
expectType<{}>(numberPick);

declare const stringOrBooleanPick: ConditionalPickDeep<Example, string | boolean>;
expectType<{
a: string;
b: string | boolean;
c: {
d: string;
e: {h: string | boolean};
j: boolean;
literal: 'foo';
string: string;
stringOrBoolean: string | boolean;
object: {
string: string;
subObject: {
string: string;
};
};
}>(stringOrBooleanPick);

declare const stringOrBooleanPickOnly: ConditionalPickDeep<Example, string | boolean, {condition: 'equality'}>;
expectType<{b: string | boolean; c: {e: {h: string | boolean}}}>(stringOrBooleanPickOnly);
expectType<{stringOrBoolean: string | boolean}>(stringOrBooleanPickOnly);

declare const arrayPick: ConditionalPickDeep<Example, string[]>;
expectType<{array: string[]; tuples: ['foo', 'bar']}>(arrayPick);

declare const arrayEqualityPick: ConditionalPickDeep<Example, string[], {condition: 'equality'}>;
expectType<{array: string[]}>(arrayEqualityPick);

declare const tuplePick: ConditionalPickDeep<Example, ['foo', 'bar']>;
expectType<{tuples: ['foo', 'bar']}>(tuplePick);

declare const instancePick: ConditionalPickDeep<Example, ClassA>;
expectType<{instanceA: ClassA}>(instancePick);

declare const classPick: ConditionalPickDeep<Example, typeof ClassA>;
expectType<{ClassA: typeof ClassA}>(classPick);

declare const functionPick: ConditionalPickDeep<Example, (...args: string[]) => string>;
expectType<{function: (...args: string[]) => string}>(functionPick);

declare const mapPick: ConditionalPickDeep<Example, Map<string, string>>;
expectType<{map: Map<string, string>}>(mapPick);

declare const setPick: ConditionalPickDeep<Example, Set<string>>;
expectType<{set: Set<string>}>(setPick);

0 comments on commit 9960ba4

Please sign in to comment.