복잡한 매핑 유형 분류
15037 단어 typescriptwebdevtutorial
에서 님의 비디오를 시청하는 동안
event
에서 GlobalReducer
의 유형을 이해하려고 애쓰면서 꽤 막혔습니다.이 유형에는 많은 부분이 있으며 적어도 나에게는 그 중 특별히 직관적인 부분이 없습니다. 그것을 이해하려면 먼저 그것을 더 작은 조각으로 분해해야 했습니다.
다음은 해당 프로세스의 연습입니다.
먼저 리듀서 유형을 추가하고 제거할 수 있는
GlobalReducerEvent
가 있습니다.interface GlobalReducerEvent {
ADD_TODO: {
text: string
}
LOG_IN: {
email: string
}
DELETE_TODO: {
todo_id: number
}
}
type ReducerEvent = ... /* what we're about to build */
type GlobalReducer<TState> = (
state: TState,
event: ReducerEvent
) => TState
우리는
GlobalReducer
가 어떤 이벤트가 포함되어 있는지에 따라 유형 검사를 수행하기를 원합니다. 이를 위해 GlobalReducerEvent
를 사용자 영역 코드에서 유용한 유형으로 매핑할 수 있는 몇 가지 재미있는 TypeScript 기능을 사용해야 합니다.// this is our target type
type ReducerEvent = ({
type: "ADD_TODO";
text: string;
}) | ({
type: "LOG_IN";
email: string;
}) | ({
type: "DELETE_TODO";
todo_id: number;
})
ReducerEvent
(event
의 유형)까지 빌드하는 것이 여기서 우리의 최종 목표입니다.keyof
부터 시작하여 모든 이벤트의 합집합 유형을 얻을 수 있습니다.// What are our different types of events?
type EventUnion = keyof GlobalReducerEvent;
/*
type EventUnion = 'ADD_TODO' | 'LOG_IN' | 'DELETE_TODO'
*/
그것은 최종 결과에서 서로 다른 두 위치에서 사용되기 때문에 퍼즐의 중요한 조각입니다.
다음 몇 단계는 중간 유형의 정렬을 구축하는 것입니다. 원래 유형을 대상 유형에 매핑하는 데 도움이 되는 유형입니다.
in
를 사용하여 EventUnion
의 값에 대한 색인 서명을 만들 수 있습니다(기억은 keyof GlobalReducerEvent
). 지금은 각 키를 any
로 입력합니다.// Gather up the types of events
// (we'll replace the `any` in a moment)
type EventTypes = {
[EventType in EventUnion]: any
};
/*
type EventTypes = {
ADD_TODO: any;
LOG_IN: any;
DELETE_TODO: any;
}
same as doing:
type EventTypes = {
[EventType in keyof GlobalReducerEvent]: any
}
*/
이제
any
로 입력하는 대신 개체에 키를 지정해 보겠습니다. 이 개체는 우리가 매핑하려는 값을 향해 빌드를 시작할 것입니다.각 이벤트에는 값이 해당 이름과 일치하는
type
가 있어야 합니다. EventType
는 이벤트 이름에 대한 참조이므로 개체 유형( { type: EventType }
)에서 사용할 수 있습니다.// Event type keyed to itself as an object
// (weird intermediate type, stick with me here)
type EventTypesWithSelf = {
[EventType in keyof GlobalReducerEvent]: {
type: EventType
}
};
/*
type EventTypesWithSelf = {
ADD_TODO: {
type: "ADD_TODO";
};
LOG_IN: {
type: "LOG_IN";
};
DELETE_TODO: {
type: "DELETE_TODO";
};
}
*/
각 이벤트에는 함께 이동해야 하는 데이터를 정의하는 유형이 있습니다. 예를 들어
ADD_TODO
에는 수행할 작업을 구성하는 약간의 텍스트가 필요합니다. 따라서 ADD_TODO: { text: string }
. 이 다음 부분에서는 각 이벤트의 데이터에 대한 입력을 접을 것입니다.intersection type literal (
&
)을 사용하여 각 이벤트 유형({type: 'ADD_TODO'}
)과 해당 데이터 유형({text: string}
)을 결합할 수 있습니다.// Event type keyed to itself and its data
// (still looks weird, but starting to take shape)
type EventTypesWithSelfAndData = {
[EventType in keyof GlobalReducerEvent]: {
type: EventType
} & GlobalReducerEvent[EventType]
};
/*
type EventTypesWithSelfAndData = {
ADD_TODO: {
type: "ADD_TODO";
} & {
text: string;
};
LOG_IN: {
type: "LOG_IN";
} & {
email: string;
};
DELETE_TODO: {
type: "DELETE_TODO";
} & {
todo_id: number;
};
}
which you can think of as:
type EventTypesWithSelfAndData = {
ADD_TODO: {
type: "ADD_TODO";
text: string;
};
LOG_IN: {
type: "LOG_IN";
email: string;
};
DELETE_TODO: {
type: "DELETE_TODO";
todo_id: number;
};
}
*/
마지막 부분에 도달하기 전에 유형 객체indexed access에 대한 머리를 둘러보겠습니다.
이 작업은 JavaScript 개체에서 키 값에 액세스하는 것과 매우 유사합니다. 이전 단계의 유형을 사용하여
'ADD_TODO'
유형만 가져올 수 있습니다.// Let's try an indexed access of EventTypesWithSelfAndData
type AddTodoType = EventTypesWithSelfAndData['ADD_TODO']
/*
type AddTodoType = {
type: "ADD_TODO";
} & {
text: string;
}
*/
JavaScript 개체 액세스가 작동하는 방식과 다른 점은 개별 값 대신 공용체 유형을 전달하여 입증됩니다.
// What if we try to access multiple types at once with a union
type SomeEventTypes = EventTypesWithSelfAndData['ADD_TODO' | 'DELETE_TODO']
/*
type SomeEventTypes = ({
type: "ADD_TODO";
} & {
text: string;
}) | ({
type: "DELETE_TODO";
} & {
todo_id: number;
})
*/
결과 형식은 합집합 값에서 인덱싱된 형식으로만 구성된 합집합 형식입니다.
우리는 모든 이벤트 유형의 합집합인
keyof GlobalReducerEvent
로 인덱싱된 액세스를 수행하여 이를 한 단계 더 발전시킬 수 있습니다.// That means we can pass in a union of all our event type names
// to get a union of all the type signatures.
type AllEventTypes = EventTypesWithSelfAndData[keyof GlobalReducerEvent]
/*
type AllEventTypes = ({
type: "ADD_TODO";
} & {
text: string;
}) | ({
type: "LOG_IN";
} & {
email: string;
}) | ({
type: "DELETE_TODO";
} & {
todo_id: number;
})
which, you might remember, is equivalent to this:
type AllEventTypes = ({
type: "ADD_TODO";
text: string;
}) | ({
type: "LOG_IN";
email: string;
}) | ({
type: "DELETE_TODO";
todo_id: number;
})
*/
마지막 예제는 이 전체 ReducerEvent와 동일합니다. 우리는 그것을 모든 구성 요소로 구성했습니다. 재미있는!
전체를 다시 한 번 살펴보겠습니다.
type ReducerEvent = {
[EventType in keyof GlobalReducerEvent]: {
type: EventType
} & GlobalReducerEvent[EventType]
}[keyof GlobalReducerEvent]
바라건대 이것의 모든 다른 부분을 살펴보니 마술처럼 보이기보다는 추론할 수 있는 무언가처럼 보입니다.
이 게시물이 마음에 드셨다면 joining my newsletter을 고려하거나 에서 저를 팔로우하세요. 이것이 도움이 되었거나 질문이 있는 경우 언제든지 저에게 메모를 남겨주세요. 당신의 의견을 듣고 싶습니다!
이것으로 더 자세히 놀고 싶습니까? the TypeScript Playground에서 확인하세요.
GeoJango Maps on Unsplash의 표지 사진
Reference
이 문제에 관하여(복잡한 매핑 유형 분류), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/jbranchaud/breaking-down-a-complex-mapped-type-in5텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)