-
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.
feat(RequiredExactlyOne): Add
RequiredExactlyOne
(#74)
* feat(RequiredExactlyOne): Add RequiredExactlyOne type * test(RequiredExactlyOne): Add RequiredExactlyOne test * docs(RequiredExactlyOne): Add RequiredExactlyOne docs
- Loading branch information
1 parent
b0c212d
commit c90dd07
Showing
7 changed files
with
158 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
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,44 @@ | ||
# RequiredExactlyOne\<T, K> | ||
|
||
## 개요 | ||
|
||
지정된 키 중 정확히 하나를 필수로 만들고, 나머지 지정된 키는 never로 설정하며, 나머지 타입은 변경되지 않는 새로운 타입을 생성해요 | ||
|
||
## 문법 | ||
|
||
```ts | ||
type RequiredExactlyOne<T, K extends keyof T> = Simplify< | ||
Omit<T, K> & | ||
{ | ||
[P in K]: Required<Pick<T, P>> & Partial<Record<Exclude<K, P>, never>>; | ||
}[K] | ||
>; | ||
``` | ||
|
||
- **T**: 키를 선택할 원본 타입이에요. | ||
- **K**: 원본 타입 T에서 필수로 설정될 키와 never로 설정될 나머지 키를 포함하는 키의 집합이에요. | ||
|
||
## 예제 | ||
|
||
```ts | ||
type T0 = { | ||
a?: number; | ||
b: string; | ||
c: boolean; | ||
}; | ||
type E0 = RequiredExactlyOne<T0, 'a'>; // { a: number; b: string; c: boolean } | ||
|
||
type T1 = { | ||
a?: number; | ||
b: string; | ||
c: boolean; | ||
}; | ||
type E1 = RequiredExactlyOne<T1, 'a' | 'b'>; // { a: number; b?: never; c: boolean } | { a?: never; b: string; c: boolean } | ||
|
||
type T2 = { | ||
a: number; | ||
b: string; | ||
c: boolean; | ||
}; | ||
type E2 = RequiredExactlyOne<T2, 'a' | 'b'>; // { a: number; b?: never; c: boolean } | { a?: never; b: string; c: boolean } | ||
``` |
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,44 @@ | ||
# RequiredExactlyOne\<T, K> | ||
|
||
## Overview | ||
|
||
Creates a new type where exactly one of the specified keys is made required, and the other specified keys are set to never, while keeping the rest of the type unchanged. | ||
|
||
## Syntax | ||
|
||
```ts | ||
type RequiredExactlyOne<T, K extends keyof T> = Simplify< | ||
Omit<T, K> & | ||
{ | ||
[P in K]: Required<Pick<T, P>> & Partial<Record<Exclude<K, P>, never>>; | ||
}[K] | ||
>; | ||
``` | ||
|
||
- **T**: The original type from which keys are being picked. | ||
- **K**: The keys from the original type `T` that one of the `K` is made required, and the other specified keys are set to never. | ||
|
||
## Example | ||
|
||
```ts | ||
type T0 = { | ||
a?: number; | ||
b: string; | ||
c: boolean; | ||
}; | ||
type E0 = RequiredExactlyOne<T0, 'a'>; // { a: number; b: string; c: boolean } | ||
|
||
type T1 = { | ||
a?: number; | ||
b: string; | ||
c: boolean; | ||
}; | ||
type E1 = RequiredExactlyOne<T1, 'a' | 'b'>; // { a: number; b?: never; c: boolean } | { a?: never; b: string; c: boolean } | ||
|
||
type T2 = { | ||
a: number; | ||
b: string; | ||
c: boolean; | ||
}; | ||
type E2 = RequiredExactlyOne<T2, 'a' | 'b'>; // { a: number; b?: never; c: boolean } | { a?: never; b: string; c: boolean } | ||
``` |
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,29 @@ | ||
import { Simplify } from './Simplify'; | ||
|
||
/** | ||
* @description | ||
* Creates a new type where exactly one of the specified keys is made required, | ||
* and the other specified keys are set to never, while keeping the rest of the type unchanged. | ||
* | ||
* @template T - The original type from which keys are being picked. | ||
* @template K - The keys from the original type `T` that one of the `K` is made required and the others are set to never. | ||
* | ||
* @returns | ||
* A new type where exactly one of the specified keys is required, | ||
* and the other specified keys are set to never, with the rest of the properties from the original type unchanged. | ||
* | ||
* @example | ||
* type T0 = { | ||
* a: number; | ||
* b: string; | ||
* c: boolean; | ||
* } | ||
* | ||
* type E0 = RequiredExactlyOne<T0, 'a' | 'b'>; // { a: number; b?: never; c: boolean } | { a?: never; b: string; c: boolean } | ||
*/ | ||
export type RequiredExactlyOne<T, K extends keyof T> = Simplify< | ||
Omit<T, K> & | ||
{ | ||
[P in K]: Required<Pick<T, P>> & Partial<Record<Exclude<K, P>, never>>; | ||
}[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
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,32 @@ | ||
import { RequiredExactlyOne } from '@/utilities'; | ||
import { expectType } from 'tsd'; | ||
|
||
declare function requiredExactlyOne<T, K extends keyof T>(): RequiredExactlyOne< | ||
T, | ||
K | ||
>; | ||
|
||
// Should be exactly equal to original. | ||
type T0 = { | ||
a: number; | ||
b: string; | ||
c: boolean; | ||
}; | ||
type E0 = { a: number; b: string; c: boolean }; | ||
expectType<E0>(requiredExactlyOne<T0, 'a'>()); | ||
|
||
// Should require exactly one of 'a' or 'b'. | ||
type T1 = T0; | ||
type E1 = | ||
| { a: number; b?: never; c: boolean } | ||
| { a?: never; b: string; c: boolean }; | ||
expectType<E1>(requiredExactlyOne<T1, 'a' | 'b'>()); | ||
|
||
// Should require 'a' to be present. | ||
type T2 = { | ||
a?: number; | ||
b: string; | ||
c: boolean; | ||
}; | ||
type E2 = { a: number; b: string; c: boolean }; | ||
expectType<E2>(requiredExactlyOne<T2, 'a'>()); |