Pesquisei de várias maneiras, mas não consegui encontrar mais informações sobre tipagem condicional. Estou tentando criar um tipo chamado ChatItemMessage
e ele tem 2 índices, type
e value
.
Este é o código atual:
type ChatItemMessage = {
type: ChatItemMessageType;
value: ChatMessage | ChatDate;
};
enum ChatItemMessageType {
Date = "date",
Message = "message",
}
type ChatMessage = {
id: number;
};
type ChatDate = {
date: string;
};
O que estou tentando fazer é definir condicionalmente o tipo value
com base no valor de type
:
export type ChatItemMessage = {
type: ChatItemMessageType;
value: (ChatItemMessage['type'] extends ChatItemMessageType.Message ? ChatMessage : ChatDate);
};
Isso não está funcionando, eu também tentei (e outras variações):
export type ChatItemMessage<T extends ChatItemMessageType> = {
type: T;
value: (T extends ChatItemMessageType.Message ? ChatMessage : ChatDate);
};
No meu código estou fazendo então:
declare const data: ChatItemMessage[]
data.map(
message => message.type === ChatItemMessageType.Date ?
message.value.date : // error!
// ~~~~ <-- Property 'date' does not exist on type 'ChatMessage'.
message.value.id.toFixed() // error!
// ~~ <-- Property 'id' does not exist on type 'ChatDate'.
);
O que eu quero é que message.value
seja ChatMessage
porque já verifiquei se é message.type === ChatItemMessageType.Message
, mas o IDE está sempre dizendo que é ChatDate
.
A ideia é que o IDE e qualquer desenvolvedor saibam que if type = ChatItemMessageType.Message
then value = ChatMessage
, else (nesse caso) será ChatDate
, então novos erros devem aparecer se o desenvolvedor tiver o tipo errado em mente no tempo de execução.
Nem tenho certeza se isso pode ser alcançado ou não. Se precisar de mais informações, me avise!
Para que isso funcione, você precisa
ChatItemMessage
ser uma união discriminada , onde cada membro da união corresponde a uma das possibilidades para parestype
/value
, de modo quetype
possa ser usada como uma propriedade discriminante . Assim:Depois de fazer isso, seu código funcionará conforme escrito:
Link do playground para o código