Skip to content

Commit

Permalink
feat(types): Merge, Invert, NegativeNumber 타입 추가 (#645)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssi02014 authored Dec 28, 2024
1 parent 666b883 commit 1aa0e45
Show file tree
Hide file tree
Showing 17 changed files with 172 additions and 33 deletions.
5 changes: 5 additions & 0 deletions .changeset/clever-points-tap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@modern-kit/types': minor
---

feat(types): Merge, Invert, NegativeNumber 타입 추가 - @ssi02014

This file was deleted.

4 changes: 0 additions & 4 deletions packages/types/src/ExtendOmittedProperties/index.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/types/src/ExtractMapType/ExtractMapType.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, it, expectTypeOf } from 'vitest';
import { ExtractMapType } from '.';

describe('ExtractMapType', () => {
it('should infer the generic type of a Map', () => {
it('Map의 제네릭 타입을 올바르게 추론해야 합니다.', () => {
const key = 'foo' as 'foo' | 'bar';
const value = 1 as 1 | 2 | 3;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, it, expectTypeOf } from 'vitest';
import { ExtractNestedArrayType } from '.';

describe('ExtractNestedArrayType', () => {
it('should correctly extract the nested array type when all elements are numbers', () => {
it('모든 요소가 숫자인 중첩 배열에서 올바르게 타입을 추출해야 합니다.', () => {
const arr = [1, 2, [3, 4, [5, 6]]]; // (number | (number | number[])[])[]
const flattenArray = arr.flat(2); // number[]

Expand All @@ -11,7 +11,7 @@ describe('ExtractNestedArrayType', () => {
expectTypeOf(flattenArray).toEqualTypeOf<extractedType[]>();
});

it('should correctly extract the nested array type when elements are of mixed types', () => {
it('요소가 혼합된 타입인 중첩 배열에서 올바르게 타입을 추출해야 합니다.', () => {
const arr = [1, 2, ['string', 4, [true, 6]]]; // (number | (string | number | (number | boolean)[])[])[]
const flattenArray = arr.flat(3); // (string | number | boolean)[]

Expand Down
14 changes: 14 additions & 0 deletions packages/types/src/Integer/Integer.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { describe, it, expectTypeOf } from 'vitest';
import { Integer } from '.';

describe('Integer', () => {
it('정수라면 해당 타입을 반환하고, 정수가 아니라면 never를 반환해야 합니다. ', () => {
const validInteger1: Integer<1> = 1; // 양의 정수
const validInteger2: Integer<-1> = -1; // 음의 정수
const invalidInteger: Integer<1.5> = null as unknown as Integer<1.5>;

expectTypeOf(validInteger1).toEqualTypeOf<1>();
expectTypeOf(validInteger2).toEqualTypeOf<-1>();
expectTypeOf(invalidInteger).toEqualTypeOf<never>();
});
});
10 changes: 10 additions & 0 deletions packages/types/src/Integer/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/**
* @description 숫자 타입이 정수인지 확인하는 타입
*
* @template T - 검사할 숫자 타입
* @returns 입력된 숫자가 정수이면 해당 타입을 반환하고, 소수점이 있으면 never를 반환
*
* @example
* type ValidInteger = Integer<1>; // 1
* type InvalidInteger = Integer<1.5>; // never
*/
export type Integer<T extends number> = `${T}` extends `${string}.${string}`
? never
: T;
15 changes: 15 additions & 0 deletions packages/types/src/Invert/Invert.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { describe, it, expectTypeOf } from 'vitest';
import { Invert } from '.';

describe('Invert', () => {
it('객체의 key와 value를 서로 바꾼 새로운 타입을 반환해야 합니다.', () => {
const originObj = { foo: 'a', bar: 'b' } as const;

const invertedObj: Invert<typeof originObj> = { a: 'foo', b: 'bar' };

expectTypeOf(invertedObj).toEqualTypeOf<{
readonly a: 'foo';
readonly b: 'bar';
}>();
});
});
13 changes: 13 additions & 0 deletions packages/types/src/Invert/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @description 객체의 key와 value을 서로 바꾸는 타입입니다.
*
* @template T - 타입을 변경 할 객체 타입
* @returns 원본 객체의 키와 값이 서로 바뀐 새로운 타입을 반환합니다
*
* @example
* type originObj = { a: "x", b: "y" };
* type invertedObj = Invert<origin>; // { x: "a", y: "b" }
*/
export type Invert<T extends Record<PropertyKey, PropertyKey>> = {
[K in keyof T as T[K]]: K;
};
23 changes: 23 additions & 0 deletions packages/types/src/Merge/Merge.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { describe, it, expectTypeOf } from 'vitest';
import { Merge } from '.';

describe('Merge', () => {
it('두 개의 객체 타입을 병합하여 새로운 객체 타입을 반환해야 합니다.', () => {
type MergedType = Merge<
{ a: string; b: number },
{ b: string; c: boolean }
>; // { a: string; b: string; c: boolean }

const obj: MergedType = {
a: 'a',
b: 'b',
c: true,
};

expectTypeOf(obj as { a: string; b: string; c: boolean }).toEqualTypeOf<{
a: string;
b: string;
c: boolean;
}>();
});
});
21 changes: 21 additions & 0 deletions packages/types/src/Merge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @description 두 객체 타입을 병합하는 타입입니다. 이때, 겹치는 프로퍼티는 두 번째 타입의 타입으로 대체됩니다.
*
* @template A - 첫 번째 타입
* @template B - 두 번째 타입
*
* @example
* type A = { a: string, b: number }
* type B = { b: string, c: boolean }
* type Result = Merge<A, B>
*
* // 동작 원리와 순서
* // 1. Result = Merge<A, B>
* // 2. Result = Omit<A, 'b' | 'c'> & B
* // 3. Result = { a: string } & B
* // 4. Result = { a: string, b: string, c: boolean }
*/
export type Merge<
A extends Record<PropertyKey, any>,
B extends Record<PropertyKey, any>
> = Omit<A, keyof B> & B;
18 changes: 18 additions & 0 deletions packages/types/src/NaturalNumber/NaturalNumber.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { describe, it, expectTypeOf } from 'vitest';
import { NaturalNumber } from '.';

describe('NaturalNumber', () => {
it('자연수라면 해당 타입을 반환하고, 자연수가 아니라면 never를 반환해야 합니다. ', () => {
const validNaturalNumber: NaturalNumber<1> = 1;

const invalidNaturalNumber1: NaturalNumber<0> = null as NaturalNumber<0>;
const invalidNaturalNumber2: NaturalNumber<-1> = null as NaturalNumber<-1>;
const invalidNaturalNumber3: NaturalNumber<1.5> =
null as NaturalNumber<1.5>;

expectTypeOf(validNaturalNumber).toEqualTypeOf<1>();
expectTypeOf(invalidNaturalNumber1).toEqualTypeOf<never>();
expectTypeOf(invalidNaturalNumber2).toEqualTypeOf<never>();
expectTypeOf(invalidNaturalNumber3).toEqualTypeOf<never>();
});
});
20 changes: 15 additions & 5 deletions packages/types/src/NaturalNumber/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { Integer } from 'Integer';

export type NaturalNumber<T extends number> = Integer<T> extends never
? never
: `${T}` extends `-${string}` | '0'
/**
* @description 자연수를 나타내는 타입입니다 (0보다 큰 양의 정수).
*
* @template T - 검사할 숫자 타입
* @returns 입력된 숫자 T가 자연수인 경우 해당 타입을 반환하고,유효하지 않은 자연수인 경우 never를 반환합니다.
* @example
* type ValidNaturalNumber = NaturalNumber<1>; // 1
* type InvalidNaturalNumber1 = NaturalNumber<0>; // never
* type InvalidNaturalNumber2 = NaturalNumber<-1>; // never
* type InvalidNaturalNumber3 = NaturalNumber<1.5>; // never
*/
export type NaturalNumber<T extends number> = `${T}` extends
| `${number}.${number}`
| `-${string}`
| '0'
? never
: T;
18 changes: 18 additions & 0 deletions packages/types/src/NegativeNumber/NegativeNumber.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { describe, it, expectTypeOf } from 'vitest';
import { NegativeNumber } from '.';

describe('NegativeNumber', () => {
it('음수라면 해당 타입을 반환하고, 음수가 아니라면 never를 반환해야 합니다. ', () => {
const validNegative: NegativeNumber<-1> = -1;

const invalidNegative1: NegativeNumber<1> =
null as unknown as NegativeNumber<1>; // 양수

const invalidNegative2: NegativeNumber<1.5> =
null as unknown as NegativeNumber<1.5>; // 소수

expectTypeOf(validNegative).toEqualTypeOf<-1>();
expectTypeOf(invalidNegative1).toEqualTypeOf<never>();
expectTypeOf(invalidNegative2).toEqualTypeOf<never>();
});
});
13 changes: 13 additions & 0 deletions packages/types/src/NegativeNumber/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @description 주어진 숫자 타입이 음수인지 확인하는 타입
*
* @template T - 검사할 숫자 타입
* @returns 입력된 타입 T가 음수인 경우 T를 반환하고, 그렇지 않으면 never를 반환
*
* @example
* type validNegativeNumber = NegativeNumber<-1>; // -1
* type invalidNegativeNumber = NegativeNumber<1>; // never
*/
export type NegativeNumber<T extends number> = `${T}` extends `-${number}`
? T
: never;
4 changes: 3 additions & 1 deletion packages/types/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
export * from './Arrayable';
export * from './ArrayWithReadonly';
export * from './ExcludeNullish';
export * from './ExtendOmittedProperties';
export * from './ExtractMapType';
export * from './ExtractNestedArrayType';
export * from './ExtractSetType';
export * from './IndexSignature';
export * from './Integer';
export * from './Invert';
export * from './Merge';
export * from './NaturalNumber';
export * from './NegativeNumber';
export * from './NonEmptyArray';
export * from './Nullable';
export * from './ObjectEntries';
Expand Down
2 changes: 1 addition & 1 deletion packages/utils/src/common/asyncNoop/asyncNoop.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest';
import { asyncNoop } from '.';

describe('asyncNoop', () => {
it('should return a Promise', () => {
it('Promise를 반환해야 합니다', () => {
expect(asyncNoop()).toBeInstanceOf(Promise);
});
});

0 comments on commit 1aa0e45

Please sign in to comment.