redux - 왜 Typescript가 오류 메시지를 던지나요: 타입에 해당 속성이 존재하지 않습니다?
나는 두 가지 코드 예제를 만들었습니다. 그들 사이의 유일한 차이점은 내가 switch 연산자에 전달하는 표현식입니다.
첫 번째 경우에는 객체 속성을 사용합니다. 그리고 잘 작동합니다.
두 번째 경우에 나는 type 변수를 만듭니다. 그리고 Typescript는 오류 메시지를 발생시킵니다:
속성 'name'은 'Action' 유형에 존재하지 않습니다.
속성 'name'은(는) 타입 '{ type: "reset"; }'에 존재하지 않습니다.
왜 이런 일이 일어나고 있나요?
객체 속성 action.type과 변수 type은 동일한 타입 'reset' | 'update'입니다.
interface State {
name: string;
cars: any[];
}
type Action = { type: 'reset' } | { type: 'update', name: string };
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'update':
return { ...state, name: action.name };
case 'reset':
return {...state, cars: [] };
default:
throw new Error();
}
}interface State {
name: string;
cars: any[];
}
type Action = { type: 'reset' } | { type: 'update', name: string };
function reducer(state: State, action: Action): State {
/**
* Create a 'type' variable
*/
const { type } = action;
switch (type) {
case 'update':
return { ...state, name: action.name };
/**
* Typescript will throw an error message
* Property 'name' does not exist on type 'Action'.
* Property 'name' does not exist on type '{ type: "reset"; }'.
*/
case 'reset':
return {...state, cars: [] };
default:
throw new Error();
}
}이미지 설명
답변 #1
기본적으로, Typescript는 변수 action과 type의 타입 간의 관계를 추적하지 않습니다. type의 타입이 좁혀질 때(예를 들어 switch 문에서 case인 경우), action의 타입도 함께 좁혀지지 않습니다.
할당 const { type }=action;에서, 컴파일러는 type: Action['type']를 추론하는데, 이는 우연히 'reset' | 'update'가 됩니다. 이후 case 표현식은 action에 대한 타입 가드 검사가 수행되지 않았기 때문에 action의 타입을 좁히지 않습니다.
이것이 원하는 방식으로 동작하려면, 컴파일러는 타입 변수 T extends Action['type']를 도입하고 type: T를 추론하면서, 동시에 action을 : Action & { type: T } 타입으로 좁혀야 합니다. 그런 다음 type의 타입이 좁혀지면, T 자체도 좁혀져야 하므로, 이 효과가 action의 타입에도 전파되어야 하는데, 여기에는 T가 포함됩니다.
모든 변수 할당 시 이렇게 새로운 타입 변수를 도입하고, 제네릭 타입 변수의 상한을 제어 흐름에 따라 좁히는 것은 타입 검사 알고리즘을 매우 복잡하게 만들 것입니다. 또한 추론된 타입을 훨씬 복잡하게 만들어 사용자가 이해하기 어렵게 만들기 때문에, TypeScript가 이를 하지 않는 것은 합리적입니다. 일반적으로, 타입 체커는 코드의 모든 증명 가능한 속성을 증명하지 않으며, 이것이 그 한 예입니다.
답변 #2
인수를 참조할 때는 전체 객체에서 타입을 추론할 수 있지만, 상수를 생성하면 타입이 단순히 "reset" | "update"로 제한되고 Action 객체 타입의 다른 정보는 사라집니다.