TypeScript에서 값을 제한하지 않고 자동 완성 유형 만들기

문제



현재 역할에서 우리는 프런트 엔드 개발자가 사용할 내부 라이브러리를 구축합니다. 우리가 짓고 있는 새로운 도서관을 위해 우리는 이전에 한 번도 해본 적이 없는 일을 해야 했습니다. 우리 라이브러리는 TypeScript에 있으며 매개변수 값에 대한 IDE 제안을 제공하고 싶었지만 실제로 해당 매개변수 값을 제한할 수 없었습니다. 그 이유는 90%의 경우 값이 몇 가지 명백한 값일 것이기 때문입니다. 그러나 나머지 10%의 경우 값이 어떻게 될지 예측할 방법이 없었습니다!

도전



해결책은 간단하다고 생각할 것입니다. 하지만 그렇지 않았습니다.

TypeScript에 익숙하다면 초기 문제는 쉬워 보입니다. 사용할 수 있는 곤충 목록을 선언해야 합니다. 이는 Union Type을 정의하여 쉽게 수행할 수 있습니다.

type Insect = 'scorpion' | 'cockroach' | 'caterpillar';


빠진 것은 새로운 곤충을 찾아서 사용하려고 하면 다음과 같은 작업을 할 수 없다는 것입니다.

const foundInsect: Insect = 'bee';


그러면 오류가 발생합니다.

음, 이러한 문자열 중 하나를 허용하는 유형이 있습니다. 맞습니까?

const foundInsect: string = 'bee';


이것은 작동하지만 이제 IDE에서 문자열 값을 추가해야 한다고 생각하기 때문에 IDE 제안을 잃게 됩니다.

다음 가정은 우리가 곤충 유형을 합집합으로 가지고 있다면 문자열 유형만 포함하지 않는 이유는 무엇입니까? 가장 먼저 해보고 싶었던 것 중 하나!

type Insect = 'scorpion' | 'cockroach' | 'caterpillar' | string;

const foundInsect: Insect = 'bee';


언뜻 보면 이것이 작동하는 것처럼 보입니다. 승인된 값 목록을 정의하고 문자열이 될 수도 있습니다.

이것은 오류를 발생시키지 않지만 밝혀졌습니다 ... 우리는 여전히 IDE 제안을 잃었습니다!

그것은 밝혀졌다

type Insect = 'scorpion' | 'cockroach' | 'caterpillar' | string;


까지 단순화된다

type Insect = string;


이는 우리에게 IDE 제안이 없음을 의미합니다!

이 문제가 오랫동안 논의된 this issue on the TypeScript GitHub repo을 발견했습니다.

문제는 마지막 세그먼트인 "문자열"이 우리가 정의한 문자열을 제외한 모든 문자열을 포함한다는 것입니다. 그렇게 함으로써 TypeScript는 우리가 미리 정의한 원래 리터럴 문자열 유형을 유지해야 한다는 것을 이해합니다.

@spcfran@manuth에서 제공하는 솔루션은 다음과 같습니다.

type LiteralUnion<T extends string | number> = T | Omit<T, T>;


어느 것이 놀라운 일입니까!

해결책



모두 함께 다음과 같이 끝납니다.

type LiteralUnion<T extends string | number> = T | Omit<T, T>;

type Insect = 'scorpion' | 'cockroach' | 'caterpillar';

const foundInsect: LiteralUnion<Insect> = 'bee';


첫 번째 유형인 LiteralUnion은 Generic입니다. 완전히 정의하려면 두 번째 유형이 필요합니다. 해당 정의에서 문자 T는 제공한 유형을 나타냅니다.

따라서 LiteralUnion은 문자열이나 숫자를 확장할 수 있는 "T"라는 또 다른 유형을 사용합니다. 그런 다음 LiteralUnion은 자신을 유형 또는 유형과 일치하지 않는 모든 것으로 정의합니다.

다소 추상적이므로 조금 더 깊이 들어가 보겠습니다.

두 번째 유형인 Insect는 우리가 작업해 온 것입니다. Union 유형이므로 값이 "A 또는 B 또는 C"가 될 수 있다고 말합니다. 이 경우 값은 scorpion OR cockroach OR caterpillar 일 수 있습니다.

다음 두 가지 유형을 결합하면 LiteralUnion<Insect> LiteralUnion의 일반 유형이 Insect가 될 것입니다. 그래서 T = 'scorpion' | 'cockroach' | 'caterpillar' . 이는 궁극적으로 LiteralUnion의 유형이 T OR OMIT T 일 때 기본적으로 type LiteralUnion = 'scorpion' | 'cockroach' | 'caterpillar' | OMIT<string, 'scorpion' | 'cockroach' | 'caterpillar'> 를 얻습니다. 이는 TypeScript가 모든 유형을 유지하기 위해 정확히 필요한 것입니다. 옵션으로 제안하는 IDE!

좋은 웹페이지 즐겨찾기