Búsqueda de sitios web

reactjs - Satisfacer a Typescript definiendo un tipo que puede ser Timestamp (de Firebase/Firestore) o Date


En un pequeño proyecto de aprendizaje que estoy construyendo con React + Typescript, estoy almacenando algunos mensajes en Firestore y mostrándolos después. Uno de los campos es una fecha, que en Firestore definí como date=timestamp. Cuando creo el mensaje en mi componente, lo creo como date=new Date()

Dado que definí date: Timestamp | Date, si renderizo los mensajes como {msg.date.seconds}, dado que Tipo Date no comparte las mismas propiedades que Timestamp, TypeScript se queja.

Mi manera de resolverlo es como muestro en la función formDate().

Pero no estoy seguro de que esa sea una buena solución. Preferiría formatDate() tipada así: const formatDate=(seconds:number):string {}. Pero no puedo encontrar una buena manera de satisfacer a TS con esa definición.

¿Hay una manera más limpia o mejor de escribirlo?

Edite mi comentario para aclarar mi duda. Inicialmente, escribí date: Timestamp, y estaba renderizando mi etiqueta p como <p> {formatDate(msg.date.seconds)}</p> ya que la propiedad date es un objeto con la forma {nanoseconds: number, seconds: number}

Pero en el momento en que defino el objeto newMessage, y genero date: new Date(), ahora "tengo que" escribir el campo date como una unión date: TimeStamp | Date, pero entonces TS se queja ya que la propiedad seconds falta en el tipo Date. Espero que esto lo aclare.

Mi código es

interface MessagesType {
  text: string;
  date: Timestamp | Date;
}

function Messages() {

  const [messages, setMessages] = useState<MessagesType[] | null>(
    null
  );
  const [messageText, setMessageText] = useState("");

  const getMessages = async () => {
    //...getting messages from Firebase
    });
    setMessages(messagesArray);
  };

//Function to format the input date, and to satisfy TS
  const formatDate = (date: Timestamp | Date): string => {
    if (date instanceof Timestamp) {
      // If it's a Timestamp, access the seconds property
      return new Date(date.seconds * 1000).toLocaleString();
    } else {
      // If it's a Date, no need to multiply by 1000
      return date.toLocaleString();
    }
  };

  const addNewMessage = async (): Promise<void> => 
    const newMessage: MessagesType = {
      text: messageText,
      date: new Date(),
    };
    // Add a new message
  };


  useEffect(() => 
    getMessages();
  }, []);

  return (
    <div>
      <h1>Messages</h1>
      
        <div>
          <input
            type="text"
            onChange={(e) => {
              setMessageText(e.target.value);
            }}
          />
          <Button onClick={sendMessage}>📤</Button>
        </div>
        {messages &&
          messages.map((msg) => {
            console.log("msg :>> ", msg);
            return (
              <div>
                <p>{msg.text}</p>
                <p>{formatDate(msg.date)}</p>
              </div>
            );
          })}
      </div>
    </div>
  );
}

export default Messages;

Aquí abajo añado el código que no está pasando la verificación de tipo:

interface MessagesType {
  text: string;
  date: Timestamp | Date;
}

function Messages() {

  const [messages, setMessages] = useState<MessagesType[] | null>(
    null
  );
  const [messageText, setMessageText] = useState("");

  const getMessages = async () => {
    //code to get messages from Firestore
    });
    setMessages(messagesArray);
  };


  const formatDate = (seconds:number): string => {
      return new Date(seconds * 1000).toLocaleString();
  };

  const addNewMessage = async (): Promise<void> => 
    const newMessage: MessagesType = {
      text: messageText,
      date: new Date(),
    };
    // code to Add a new message to Firestore
  };


  useEffect(() => 
    getMessages();
  }, []);

  return (
    <div>
      <h1>Messages</h1>
      
        <div>
          <input
            type="text"
            onChange={(e) => {
              setMessageText(e.target.value);
            }}
          />
          <Button onClick={sendMessage}>📤</Button>
        </div>
        {messages &&
          messages.map((msg) => {
            console.log("msg :>> ", msg);
            return (
              <div>
                <p>{msg.text}</p>
    {/*TS error:  Property 'seconds' does not exist on type 'Timestamp | Date' */}
                <p>{formatDate(msg.date.seconds)}</p>
              </div>
            );
          })}
      </div>
    </div>
  );
}

export default Messages;