From ba431c4de0cb8788f51a70b865fd1f8e08f73951 Mon Sep 17 00:00:00 2001 From: AshGw Date: Tue, 23 Apr 2024 17:31:41 +0100 Subject: [PATCH] feat(#83): finish `OmitByType` --- README.md | 3 +-- src/index.ts | 33 +++++++++++++++++++++++++++ tests/omit-by-type.test.ts | 46 ++++++++++++++++++++++++++++++++++++++ tests/pick-by-type.test.ts | 42 ++++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 tests/omit-by-type.test.ts create mode 100644 tests/pick-by-type.test.ts diff --git a/README.md b/README.md index 962c8602..24afbd26 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@ Collection of utility types, decorators and helper functions to bullet proof TypeScript even more. -[![release](https://github.com/AshGw/ts-roids/actions/workflows/ci.yml/badge.svg)](https://github.com/AshGw/ts-roids/actions/workflows/ci.yml) -[![tests](https://github.com/AshGw/ts-roids/actions/workflows/test.yml/badge.svg)](https://github.com/AshGw/ts-roids/actions/workflows/test.yml) +[![CI](https://github.com/AshGw/ts-roids/actions/workflows/ci.yml/badge.svg)](https://github.com/AshGw/ts-roids/actions/workflows/ci.yml) [![@latest](https://img.shields.io/npm/v/ts-roids.svg)](https://www.npmjs.com/package/ts-roids) [![npm downloads](https://img.shields.io/npm/dm/ts-utils.svg)](https://www.npmjs.com/package/ts-roids) [![bundle size](https://img.shields.io/bundlephobia/minzip/utility-types.svg)](https://www.npmjs.com/package/ts-roids) diff --git a/src/index.ts b/src/index.ts index 67d7dbe3..0fff7a14 100644 --- a/src/index.ts +++ b/src/index.ts @@ -797,6 +797,39 @@ export type FilterBy = { [K in Keys]: K extends P ? K : never; }[Keys]; +/** + * Get a set of properties from `T` whose type are not assignable to `P`. + * @example + * ````ts + * type T = { + * foo: string, + * bar: bigint | boolean, + * baz: number, + * } + * OmitByType; // Result: T + * OmitByType; // Result: { foo: string, bar: bigint | boolean } + * ```` + */ +export type OmitByType = { + [K in Keys as T[K] extends P ? never : K]: T[K]; +}; + +/** + * From ``T``, pick a set of properties whose type are assignable to ``P``. + * @example + * ````ts + * type T = { + * foo: string, + * bar: bigint | boolean, + * baz: number, + * } + * PickByType; // Result: {} + * PickByType; // Result: { baz: number } + * ```` + */ +export type PickByType = { + [K in Keys as T[K] extends P ? K : never]: T[K]; +}; export type Stretch = T extends object ? T extends infer P ? { [K in Keys

]: Stretch } diff --git a/tests/omit-by-type.test.ts b/tests/omit-by-type.test.ts new file mode 100644 index 00000000..42bfce16 --- /dev/null +++ b/tests/omit-by-type.test.ts @@ -0,0 +1,46 @@ +import { Numeric, Nullable, OmitByType, TestType } from 'src'; +import { test, expect } from 'vitest'; + +type OneLevelDeep = { + foo: boolean; + bar?: Numeric; + baz: Nullable; + fooBaz: bigint; + bazFoo: string | boolean; +}; + +test('_', () => { + const result: TestType< + OmitByType, + { + foo: boolean; + bar?: Numeric; + baz: Nullable; + bazFoo: string | boolean; + }, + true + > = true; + expect(result).toBe(true); +}); + +test('_', () => { + const result: TestType< + OmitByType, + { + bar?: Numeric; + baz: Nullable; + fooBaz: bigint; + }, + true + > = true; + expect(result).toBe(true); +}); + +test('_', () => { + const result: TestType< + OmitByType, + OneLevelDeep, + true + > = true; + expect(result).toBe(true); +}); diff --git a/tests/pick-by-type.test.ts b/tests/pick-by-type.test.ts new file mode 100644 index 00000000..7bfbaca2 --- /dev/null +++ b/tests/pick-by-type.test.ts @@ -0,0 +1,42 @@ +import { Numeric, Nullable, EmptyObject, PickByType, TestType } from 'src'; +import { test, expect } from 'vitest'; + +type OneLevelDeep = { + foo: boolean; + bar?: Numeric; + baz: Nullable; + fooBaz: bigint; + bazFoo: string | boolean; +}; + +test('_', () => { + const result: TestType< + PickByType, + { + fooBaz: bigint; + }, + true + > = true; + expect(result).toBe(true); +}); + +test('_', () => { + const result: TestType< + PickByType, + { + foo: boolean; + bazFoo: string | boolean; + }, + true + > = true; + expect(result).toBe(true); +}); + +test('_', () => { + const result: TestType< + PickByType, + EmptyObject, + true + > = true; + expect(result).toBe(true); +});