From ac6da6e074a9f18dc9136cf156e257d57be17d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gromit=20=28=EC=A0=84=EB=AF=BC=EC=9E=AC=29?= <64779472+ssi02014@users.noreply.github.com> Date: Sat, 28 Dec 2024 19:17:21 +0900 Subject: [PATCH] =?UTF-8?q?feat(types):=20DistributiveOmit=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EC=B6=94=EA=B0=80=20(#647)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/young-garlics-smile.md | 5 +++++ packages/types/src/ArrayWithReadonly/index.ts | 1 - .../DistributiveOmit/DistributiveOmit.spec.ts | 16 +++++++++++++++ packages/types/src/DistributiveOmit/index.ts | 20 +++++++++++++++++++ packages/types/src/ExtractMapType/index.ts | 9 +++++++++ .../src/ExtractSetType/ExtractSetType.spec.ts | 2 +- packages/types/src/ExtractSetType/index.ts | 14 +++++++++++++ packages/types/src/NegativeNumber/index.ts | 4 ++-- packages/types/src/ReadonlyArray/index.ts | 15 ++++++++++++++ packages/types/src/WholeNumber/index.ts | 12 +++++++++++ packages/types/src/index.ts | 3 ++- 11 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 .changeset/young-garlics-smile.md delete mode 100644 packages/types/src/ArrayWithReadonly/index.ts create mode 100644 packages/types/src/DistributiveOmit/DistributiveOmit.spec.ts create mode 100644 packages/types/src/DistributiveOmit/index.ts create mode 100644 packages/types/src/ReadonlyArray/index.ts diff --git a/.changeset/young-garlics-smile.md b/.changeset/young-garlics-smile.md new file mode 100644 index 000000000..60f160322 --- /dev/null +++ b/.changeset/young-garlics-smile.md @@ -0,0 +1,5 @@ +--- +'@modern-kit/types': minor +--- + +feat(types): DistributiveOmit 타입 추가 - @ssi02014 diff --git a/packages/types/src/ArrayWithReadonly/index.ts b/packages/types/src/ArrayWithReadonly/index.ts deleted file mode 100644 index 46c340082..000000000 --- a/packages/types/src/ArrayWithReadonly/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type ArrayWithReadonly = T[] | readonly T[]; diff --git a/packages/types/src/DistributiveOmit/DistributiveOmit.spec.ts b/packages/types/src/DistributiveOmit/DistributiveOmit.spec.ts new file mode 100644 index 000000000..472c61226 --- /dev/null +++ b/packages/types/src/DistributiveOmit/DistributiveOmit.spec.ts @@ -0,0 +1,16 @@ +import { describe, it, expectTypeOf } from 'vitest'; +import { DistributiveOmit } from '.'; + +describe('DistributiveOmit', () => { + it('유니온 타입에서 각각의 타입에 대해 Omit을 적용한 타입을 반환해야 합니다. ', () => { + const obj = { a: 1, b: 2 } as + | { a: number; b: number } + | { a: string; c: number }; + + const result: DistributiveOmit = { b: 2 }; + + expectTypeOf(result as { b: number } | { c: number }).toEqualTypeOf< + { b: number } | { c: number } + >(); + }); +}); diff --git a/packages/types/src/DistributiveOmit/index.ts b/packages/types/src/DistributiveOmit/index.ts new file mode 100644 index 000000000..5896a7b08 --- /dev/null +++ b/packages/types/src/DistributiveOmit/index.ts @@ -0,0 +1,20 @@ +/** + * @description 유니온 타입에서 각각의 타입에 대해 `Omit`을 적용하는 타입입니다. + * + * `조건부 타입`을 사용하여 `분배 법칙`처럼 동작합니다. + * + * @template T - 분배 대상이 되는 유니온 타입 + * @template K - 제거할 프로퍼티 키 + * + * @example + * type Union = { a: string } | { b: number } + * type Result = DistributiveOmit + * + * // 동작 원리와 순서 + * // 1. Result = DistributiveOmit + * // 2. Result = Omit<{ a: string }, 'a'> | Omit<{ b: number }, 'a'> + * // 3. Result = {} | { b: number } + */ +export type DistributiveOmit = T extends any + ? Omit + : never; diff --git a/packages/types/src/ExtractMapType/index.ts b/packages/types/src/ExtractMapType/index.ts index b0fea6e73..81314c276 100644 --- a/packages/types/src/ExtractMapType/index.ts +++ b/packages/types/src/ExtractMapType/index.ts @@ -1,3 +1,12 @@ +/** + * @description Map의 타입에서 키와 값의 타입을 추출하여 튜플로 반환하는 타입입니다. + * + * @template T - 타입을 추출할 Map 타입 + * @returns 입력된 타입이 Map인 경우 [키 타입, 값 타입] 형태의 튜플을 반환하고, Map이 아닌 경우 never를 반환합니다. + * @example + * type StringNumberMap = Map; + * type Extracted = ExtractMapType; // [string, number] + */ export type ExtractMapType = T extends Map ? [K, V] : never; diff --git a/packages/types/src/ExtractSetType/ExtractSetType.spec.ts b/packages/types/src/ExtractSetType/ExtractSetType.spec.ts index 37d331ced..928bf456e 100644 --- a/packages/types/src/ExtractSetType/ExtractSetType.spec.ts +++ b/packages/types/src/ExtractSetType/ExtractSetType.spec.ts @@ -2,7 +2,7 @@ import { describe, it, expectTypeOf } from 'vitest'; import { ExtractSetType } from '.'; describe('ExtractSetType', () => { - it('should infer the generic type of a Set', () => { + it('Set의 제네릭 타입을 추론해야 합니다.', () => { const arr = [1, 2, 3, 4, 5] as const; const testSet = new Set(arr); const convertedTestArr = [...testSet]; diff --git a/packages/types/src/ExtractSetType/index.ts b/packages/types/src/ExtractSetType/index.ts index 7c09a4cdf..073da6f63 100644 --- a/packages/types/src/ExtractSetType/index.ts +++ b/packages/types/src/ExtractSetType/index.ts @@ -1 +1,15 @@ +/** + * @description Set 타입에서 내부 요소의 타입을 추출하는 타입입니다. + * + * @template T - 타입을 추출할 Set 타입 + * @returns Set의 내부 요소 타입을 반환합니다. Set이 아닌 경우 never를 반환합니다. + * + * @example + * ```typescript + * type StringSet = Set; + * type Result = ExtractSetType; // string + * + * type NotASet = ExtractSetType; // never + * ``` + */ export type ExtractSetType = T extends Set ? U : never; diff --git a/packages/types/src/NegativeNumber/index.ts b/packages/types/src/NegativeNumber/index.ts index 59d81f26f..848dd3b38 100644 --- a/packages/types/src/NegativeNumber/index.ts +++ b/packages/types/src/NegativeNumber/index.ts @@ -5,8 +5,8 @@ * @returns 입력된 타입 T가 음수인 경우 T를 반환하고, 그렇지 않으면 never를 반환 * * @example - * type validNegativeNumber = NegativeNumber<-1>; // -1 - * type invalidNegativeNumber = NegativeNumber<1>; // never + * type ValidNegativeNumber = NegativeNumber<-1>; // -1 + * type InvalidNegativeNumber = NegativeNumber<1>; // never */ export type NegativeNumber = `${T}` extends `-${number}` ? T diff --git a/packages/types/src/ReadonlyArray/index.ts b/packages/types/src/ReadonlyArray/index.ts new file mode 100644 index 000000000..f201cf65e --- /dev/null +++ b/packages/types/src/ReadonlyArray/index.ts @@ -0,0 +1,15 @@ +/** + * @description 읽기 전용 배열을 나타내는 타입입니다. + * 기본 배열 타입은 더 좁은 타입의 읽기 전용 배열과 호환됩니다. + * + * @template T - 배열의 요소 타입 + * @returns 읽기 전용 배열 타입 + * @example + * ```typescript + * type MyArray = ReadonlyArray; + * + * const myArray: MyArray = [1, 2, 3]; // 허용 + * const myArray2: MyArray = [1, 2, 3] as const; // 허용 + * ``` + */ +export type ReadonlyArray = readonly T[]; diff --git a/packages/types/src/WholeNumber/index.ts b/packages/types/src/WholeNumber/index.ts index e38d420f6..c2094c3cf 100644 --- a/packages/types/src/WholeNumber/index.ts +++ b/packages/types/src/WholeNumber/index.ts @@ -1,5 +1,17 @@ import { Integer } from 'Integer'; +/** + * @description 양의 정수에 0을 포함한 숫자를 나타내는 타입입니다. + * + * @template T - 숫자 타입 매개변수 + * @returns {T} 입력된 숫자가 자연수(0 포함)인 경우 해당 타입을 반환하고, 그렇지 않으면 `never`를 반환합니다. + * + * @example + * type ValidWholeNumber1 = WholeNumber<1>; // 1 + * type ValidWholeNumber2 = WholeNumber<0>; // 0 + * type InvalidWholeNumber1 = WholeNumber<-1>; // never (음수이므로) + * type InvalidWholeNumber2 = WholeNumber<1.5>; // never (소수이므로) + */ export type WholeNumber = Integer extends never ? never : `${T}` extends `-${string}` diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index af29552ee..201cb63bb 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1,5 +1,5 @@ export * from './Arrayable'; -export * from './ArrayWithReadonly'; +export * from './DistributiveOmit'; export * from './ExcludeNullish'; export * from './ExtractMapType'; export * from './ExtractNestedArrayType'; @@ -16,5 +16,6 @@ export * from './ObjectEntries'; export * from './ObjectKeys'; export * from './Primitive'; export * from './Promiseable'; +export * from './ReadonlyArray'; export * from './Reference'; export * from './WholeNumber';