-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Lexus Drumgold <[email protected]>
- Loading branch information
1 parent
5796110
commit 816ad32
Showing
5 changed files
with
275 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/** | ||
* @file Type Tests - PickNative | ||
* @module tutils/types/tests/unit-d/PickNative | ||
*/ | ||
|
||
import type Vehicle from '#fixtures/types/vehicle' | ||
import type TestSubject from '../pick-native' | ||
|
||
describe('unit-d:types/PickNative', () => { | ||
it('should equal typescript.Pick<T, K>', () => { | ||
// Arrange | ||
type T = Vehicle | ||
type K = 'vin' | ||
|
||
// Expect | ||
expectTypeOf<TestSubject<T, K>>().toEqualTypeOf<Pick<T, K>> | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
/** | ||
* @file Type Tests - Pick | ||
* @module tutils/types/tests/unit-d/Pick | ||
*/ | ||
|
||
import type Vehicle from '#fixtures/types/vehicle' | ||
import type EmptyObject from '../empty-object' | ||
import type { tag as empty } from '../empty-object' | ||
import type Fn from '../fn' | ||
import type Indices from '../indices' | ||
import type Nilable from '../nilable' | ||
import type Nullable from '../nullable' | ||
import type Numeric from '../numeric' | ||
import type NegativeNumeric from '../numeric-negative' | ||
import type { tag as opaque } from '../opaque' | ||
import type Partial from '../partial' | ||
import type TestSubject from '../pick' | ||
import type PickNative from '../pick-native' | ||
import type Remap from '../remap' | ||
import type Stringify from '../stringify' | ||
import type UnwrapNumeric from '../unwrap-numeric' | ||
|
||
describe('unit-d:types/Pick', () => { | ||
it('should equal PickNative<T, K> if T is any', () => { | ||
// Arrange | ||
type T = any | ||
type K = keyof Vehicle | ||
|
||
// Expect | ||
expectTypeOf<TestSubject<T, K>>().toEqualTypeOf<PickNative<T, K>>() | ||
}) | ||
|
||
it('should equal Remap<T> if T is never', () => { | ||
// Arrange | ||
type T = never | ||
|
||
// Expect | ||
expectTypeOf<TestSubject<T, keyof Vehicle>>().toEqualTypeOf<Remap<T>>() | ||
}) | ||
|
||
describe('Remap<T> extends infer U', () => { | ||
it('should equal {} if HasKey<U, K> extends false', () => { | ||
expectTypeOf<TestSubject<EmptyObject, typeof empty>>().toEqualTypeOf<{}>() | ||
expectTypeOf<TestSubject<null, 'make'>>().toEqualTypeOf<{}>() | ||
expectTypeOf<TestSubject<undefined, 'model'>>().toEqualTypeOf<{}>() | ||
expectTypeOf<TestSubject<unknown, 'vin'>>().toEqualTypeOf<{}>() | ||
}) | ||
|
||
it('should equal {} if K is never', () => { | ||
// Arrange | ||
type T = Vehicle | ||
|
||
// Expect | ||
expectTypeOf<TestSubject<T, never>>().toEqualTypeOf<{}>() | ||
}) | ||
|
||
it('should equal U if K is any', () => { | ||
// Arrange | ||
type T = readonly [Vehicle, Vehicle] | ||
|
||
// Expect | ||
expectTypeOf<TestSubject<T, any>>().toEqualTypeOf<Remap<T>>() | ||
}) | ||
|
||
describe('K extends Stringify<infer N extends UnwrapNumeric<K>>', () => { | ||
it('should equal {} if HasKey<U, K> extends false', () => { | ||
expectTypeOf<TestSubject<[Vehicle], '-3' | '3'>>().toEqualTypeOf<{}>() | ||
}) | ||
|
||
it('should equal PickNative<U, K> if K intersects keyof U', () => { | ||
// Arrange | ||
type T = { readonly [x: Numeric]: Vehicle; readonly '0': Vehicle } | ||
type K1 = Numeric | ||
type K2 = '0' | ||
type Expect<K extends keyof T> = PickNative<Remap<T>, K> | ||
|
||
// Expect | ||
expectTypeOf<TestSubject<T, K1>>().toEqualTypeOf<Expect<K1>>() | ||
expectTypeOf<TestSubject<T, K2>>().toEqualTypeOf<Expect<K2>>() | ||
}) | ||
|
||
it('should equal PickNative<U, N> if N intersects keyof U', () => { | ||
// Arrange | ||
type T = readonly [Vehicle, Nilable<Vehicle>, Nullable<Vehicle>?] | ||
type K = Stringify<Indices<T>> | ||
type Expect = PickNative<Remap<T>, UnwrapNumeric<K>> | ||
|
||
// Expect | ||
expectTypeOf<TestSubject<T, K>>().toEqualTypeOf<Expect>() | ||
}) | ||
}) | ||
|
||
describe('K extends UnwrapNumeric<infer N extends Stringify<K>>', () => { | ||
it('should equal {} if HasKey<U, K> extends false', () => { | ||
// Arrange | ||
type T = { [x: NegativeNumeric]: string; [x: Numeric]: string } | ||
|
||
// Expect | ||
expectTypeOf<TestSubject<T, 2>>().toEqualTypeOf<{}>() | ||
expectTypeOf<TestSubject<T, number>>().toEqualTypeOf<{}>() | ||
}) | ||
|
||
it('should equal PickNative<U, K> if K intersects keyof U', () => { | ||
// Arrange | ||
type T = readonly [Vehicle, Nilable<Vehicle>, Nullable<Vehicle>?] | ||
type K1 = number | ||
type K2 = Indices<T> | ||
type Expect<K extends keyof Remap<T>> = PickNative<Remap<T>, K> | ||
|
||
// Expect | ||
expectTypeOf<TestSubject<T, K1>>().toEqualTypeOf<Expect<K1>>() | ||
expectTypeOf<TestSubject<T, K2>>().toEqualTypeOf<Expect<K2>>() | ||
}) | ||
|
||
it('should equal PickNative<U, N> if N intersects keyof U', () => { | ||
// Arrange | ||
type T = { readonly '0'?: Vehicle; readonly '1'?: Vehicle } | ||
type K = 0 | ||
type Expect = PickNative<Remap<T>, Stringify<K>> | ||
|
||
// Expect | ||
expectTypeOf<TestSubject<T, K>>().toEqualTypeOf<Expect>() | ||
}) | ||
}) | ||
|
||
describe('K extends string', () => { | ||
it('should equal {} if HasKey<U, K> extends false', () => { | ||
expectTypeOf<TestSubject<Vehicle, 'vrm'>>().toEqualTypeOf<{}>() | ||
}) | ||
|
||
it('should equal PickNative<U, K> if K intersects keyof U', () => { | ||
// Arrange | ||
type T = Partial<Readonly<Vehicle>> | ||
type K = 'vin' | ||
type Expect = PickNative<Remap<T>, K> | ||
|
||
// Expect | ||
expectTypeOf<TestSubject<T, K>>().toEqualTypeOf<Expect>() | ||
}) | ||
}) | ||
|
||
describe('K extends symbol', () => { | ||
type T = Readonly<Fn> | ||
|
||
it('should equal {} if HasKey<U, K> extends false', () => { | ||
expectTypeOf<TestSubject<T, typeof opaque>>().toEqualTypeOf<{}>() | ||
}) | ||
|
||
it('should equal PickNative<U, K> if K intersects keyof U', () => { | ||
// Arrange | ||
type K = typeof Symbol.hasInstance | ||
|
||
// Expect | ||
expectTypeOf<TestSubject<T, K>>().toEqualTypeOf<PickNative<T, K>>() | ||
}) | ||
}) | ||
}) | ||
|
||
describe('unions', () => { | ||
it('should distribute over unions', () => { | ||
// Arrange | ||
type T = Vehicle | readonly [Vehicle, Vehicle['vin']] | ||
type K = '1' | 'vin' | ||
type Expect = { readonly 1: Vehicle['vin'] } | { vin: Vehicle['vin'] } | ||
|
||
// Expect | ||
expectTypeOf<TestSubject<T, K>>().toEqualTypeOf<Expect>() | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/** | ||
* @file Type Definitions - PickNative | ||
* @module tutils/types/PickNative | ||
*/ | ||
|
||
/** | ||
* From `T`, pick a set of properties whose keys are in the union `K`. | ||
* | ||
* @see https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys | ||
* | ||
* @template T - Type to evaluate | ||
* @template K - Keys to select | ||
*/ | ||
type PickNative<T, K extends keyof T> = Pick<T, K> | ||
|
||
export type { PickNative as default } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/** | ||
* @file Type Definitions - Pick | ||
* @module tutils/types/Pick | ||
*/ | ||
|
||
import type IfAny from './if-any' | ||
import type IfNever from './if-never' | ||
import type IfNumber from './if-number' | ||
import type IfNumeric from './if-numeric' | ||
import type Intersection from './intersection' | ||
import type IsAny from './is-any' | ||
import type IsNever from './is-never' | ||
import type Numeric from './numeric' | ||
import type NegativeNumeric from './numeric-negative' | ||
import type PropertyKey from './property-key' | ||
import type Remap from './remap' | ||
import type Stringify from './stringify' | ||
import type UnwrapNumeric from './unwrap-numeric' | ||
|
||
/** | ||
* From `T`, pick a set of properties whose keys are in the union `K`. | ||
* | ||
* Type constituents in `K` must intersect `keyof Remap<T>`. When permitted by | ||
* indexing, property keys that are numbers and numerics (e.g. `0`, `'1'`) are | ||
* also allowed exact*ish* matches. | ||
* | ||
* @see {@linkcode Remap} | ||
* | ||
* @todo examples | ||
* | ||
* @template T - Type to evaluate | ||
* @template K - Keys to select | ||
*/ | ||
type Pick<T, K extends PropertyKey> = IsAny<T> extends true | ||
? { [H in K]: T } | ||
: IsNever<T> extends true | ||
? Remap<T> | ||
: T extends unknown | ||
? Remap<T> extends infer U | ||
? { | ||
[H in keyof U as IfAny< | ||
K, | ||
H, | ||
IfNever< | ||
Intersection< | ||
IfNumber< | ||
H, | ||
H | Stringify<H>, | ||
IfNumeric< | ||
H, | ||
NegativeNumeric extends H | ||
? H | ||
: Numeric extends H | ||
? H | ||
: H | UnwrapNumeric<H>, | ||
H | ||
> | ||
>, | ||
K | ||
>, | ||
never, | ||
H | ||
> | ||
>]: U[H] | ||
} | ||
: never | ||
: never | ||
|
||
export type { Pick as default } |