“이번 글에는 HackaTalk 개발 중 타이핑을 보완하는 상황에서 어떤 문제와 해결책을 도출했는지에 대해작성하려고 합니다.”
enum MessageType {
Message,
Photo,
}export interface Chat {
id: string;
sender: User;
messageType: MessageType;
message?: string;
photo?: string;
created?: Date;
updated?: Date;
}
기존에 위처럼 작성되었던 Chat 타입을 보며 개선이 필요하여 해당 PR을 날렸습니다. 위에서 보시면 앞으로 채팅 MessageType은 계속 늘어날 것이고 MessageType에 따라서 안에 들어갈 내용이 달라질 것 입니다. 따라서 photo가 있을 수도 있고 message가 있을 수도 있지만 타입에 따라서 각자가 공존하지 않을 수 있습니다. 현재 상태에서는 MessageType.Message 일 때에는 message만 들어오고 MessageType.Photo는 photo만 들어온다고 가정하겠습니다.
역시나 가장 느슨하게 타이핑을 작성하는 방법은 위처럼 message? 와 photo?를 주는 것 입니다. 누가 보면 굉장히 성의 없다고 할 수 있겠죠?
지금부터 이를 보완해보겠습니다.

- 우선 공통적으로 들어가는
Chat타입을 정의합니다.
export interface ChatCommon<T extends MessageType = MessageType.Message> {
id: string;
sender: User;
messageType: T;
created?: Date;
updated?: Date;
}defaultMessageType은MessageType.Message이고 이는ChatCommon에 아무런 generic이 들어가지 않을 때 사용합니다.messageType은 generic type 변수를 할당받고 있습니다.
2. 각각 extend를 받아서 type을 정의합니다.
interface Message<MessageType.Message> extends ChatCommon<T> {
message: string;
}interface Photo<MessageType.Photo> extends ChatCommon<T> {
photo: string;
}
- 각각의 다른 Message 타입들은 본인들의 generic type을
ChatCommon에 넘겨줍니다.
3. Conditional Typing으로 여러개의 메시지 타입을 묶어줍니다.
export type ChatProps<T extends MessageType = MessageType.Message>
= T extends MessageType.Message
? Message<T>
: T extends MessageType.Photo
? Photo<T>
: ChatCommon<T>;ChatProps은 조건에 따라서 지정된 타입을 가질 수 있게 됩니다.
4. Chat이란 타입의 변수를 배열 같은 곳에서 포괄적으로 가지고 있기 위해 추가로 아래 타입을 지정해줍니다.
type ChatType = MessageType.Message | MessageType.Photo;5. 마지막으로 아래와 같이 해보았습니다.
export type Chat = ChatProps<ChatType>;결과는 다음과 같습니다.

messageType이 `Photo일 때 `message가 없다고 나옵니다.
더 나은 방법으로 위 문제를 풀 수 있을 것 같은데 당장에는 위와 같은 방법으로 작업을 해보았습니다. 보완해서 PR을 날려주시면 언제나 환영입니다 🎉
