TypeScript에서 스위치 블록이 완전한지 어떻게 확인합니까?
몇 가지 코드가 있습니다.
enum Color {
Red,
Green,
Blue
}
function getColorName(c: Color): string {
switch(c) {
case Color.Red:
return 'red';
case Color.Green:
return 'green';
// Forgot about Blue
}
throw new Error('Did not expect to be here');
}
Color.Blue
사건 을 처리하는 것을 잊었고 컴파일 오류가 발생하는 것을 선호합니다. TypeScript가이를 오류로 표시하도록 코드를 구성하려면 어떻게해야합니까?
이를 위해 우리는 never
발생하지 않아야하는 값을 나타내는 유형 (TypeScript 2.0에서 도입)을 사용합니다.
첫 번째 단계는 함수를 작성하는 것입니다.
function assertUnreachable(x: never): never {
throw new Error("Didn't expect to get here");
}
그런 다음 default
케이스 (또는 스위치 외부)에서 사용합니다.
function getColorName(c: Color): string {
switch(c) {
case Color.Red:
return 'red';
case Color.Green:
return 'green';
}
return assertUnreachable(c);
}
이 시점에서 오류가 표시됩니다.
return assertUnreachable(c);
~~~~~~~~~~~~~~~~~~~~~
Type "Color.Blue" is not assignable to type "never"
오류 메시지는 전체 스위치에 포함하는 것을 잊은 경우를 나타냅니다! 여러 값을 생략 한 경우 예를 들어에 대한 오류가 표시 Color.Blue | Color.Yellow
됩니다.
을 사용하는 경우 호출 앞에 strictNullChecks
필요합니다 (그렇지 않으면 선택 사항 임).return
assertUnreachable
원한다면 조금 더 멋지게 만들 수 있습니다. 예를 들어 판별 된 공용체를 사용하는 경우 디버깅 목적으로 assertion 함수에서 판별 속성을 복구하는 것이 유용 할 수 있습니다. 다음과 같이 보입니다.
// Discriminated union using string literals
interface Dog {
species: "canine";
woof: string;
}
interface Cat {
species: "feline";
meow: string;
}
interface Fish {
species: "pisces";
meow: string;
}
type Pet = Dog | Cat | Fish;
// Externally-visible signature
function throwBadPet(p: never): never;
// Implementation signature
function throwBadPet(p: Pet) {
throw new Error('Unknown pet kind: ' + p.species);
}
function meetPet(p: Pet) {
switch(p.species) {
case "canine":
console.log("Who's a good boy? " + p.woof);
break;
case "feline":
console.log("Pretty kitty: " + p.meow);
break;
default:
// Argument of type 'Fish' not assignable to 'never'
throwBadPet(p);
}
}
예상 한 모든 경우를 처리했는지 확인하기 위해 컴파일 타임 안전성을 확보하기 때문에 이것은 좋은 패턴입니다. 그리고 정말로 범위를 벗어난 속성 (예 : 일부 JS 호출자가 new를 구성 species
)을 얻는 경우 유용한 오류 메시지를 표시 할 수 있습니다.
내가하는 일은 오류 클래스를 정의하는 것입니다.
export class UnreachableCaseError extends Error {
constructor(val: never) {
super(`Unreachable case: ${val}`);
}
}
그런 다음 기본 경우이 오류를 발생시킵니다.
function meetPet(p: Pet) {
switch(p.species) {
case "canine":
console.log("Who's a good boy? " + p.woof);
break;
case "feline":
console.log("Pretty kitty: " + p.meow);
break;
default:
// Argument of type 'Fish' not assignable to 'never'
throw new UnreachableCaseError(dataType);
}
}
throw
절에 기본 구문 강조 표시가 있기 때문에 읽기가 더 쉽다고 생각합니다 .
You don't need to use never
or add anything to the end of your switch
.
If
- Your
switch
statement returns in each case - You have the
strictNullChecks
typescript compilation flag turned on - Your function has a specified return type
- The return type is not
undefined
orvoid
You will get an error if your switch
statement is non-exhaustive as there will be a case where nothing is returned.
From your example, if you do
function getColorName(c: Color): string {
switch(c) {
case Color.Red:
return 'red';
case Color.Green:
return 'green';
// Forgot about Blue
}
}
You will get the following compilation error:
Function lacks ending return statement and return type does not include
undefined
.
Building on top of Ryan's answer, I discovered here that there is no need for any extra function. We can do directly:
function getColorName(c: Color): string {
switch (c) {
case Color.Red:
return "red";
case Color.Green:
return "green";
// Forgot about Blue
default:
const _exhaustiveCheck: never = c;
throw new Error("How did we get here?");
}
}
You can see it in action here in TS Playground
Create a custom function instead of using a switch
statement.
export function exhaustSwitch<T extends string, TRet>(
value: T,
map: { [x in T]: () => TRet }
): TRet {
return map[value]();
}
Example usage
type MyEnum = 'a' | 'b' | 'c';
const v = 'a' as MyEnum;
exhaustSwitch(v, {
a: () => 1,
b: () => 1,
c: () => 1,
});
If you later add d
to MyEnum
, you will receive an error Property 'd' is missing in type ...
ReferenceURL : https://stackoverflow.com/questions/39419170/how-do-i-check-that-a-switch-block-is-exhaustive-in-typescript
'Programing' 카테고리의 다른 글
Java 8-지루한 수집 방법 생략 (0) | 2020.12.30 |
---|---|
하나의 PostgreSQL 쿼리에서 여러 WITH 문을 사용하는 방법은 무엇입니까? (0) | 2020.12.30 |
asp.net 웹 메소드와 wcf 서비스의 차이점은 무엇입니까? (0) | 2020.12.30 |
이벤트 처리기에 추가 매개 변수를 전달하는 C #? (0) | 2020.12.30 |
JTable을 지우는 방법 (0) | 2020.12.30 |