Building Attachment and Image for BufferUnderflow
Modeling Attachment and Image#
Imagine trying to describe a UI issue without using images. In many cases text alone is not enough to clearly explain a problem. That's where attachments come in: attachments are files that can be attached to a question or answer to enhance their content.
Answers and questions can have multiple attachments, and an attachment can be reused across various answers and questions. The diagram below highlights the Attachment
interface and its relationship to the other entities in our program:

Images are the only supported attachment type in BufferUnderflow, but as our app grows, we may want to introduce more options: videos, PDFs, Word documents, etc. Because we anticipate these additions, we've decided to create an Attachment
interface that represents any attachment. All attachment classes that we add in the future will implement the Attachment
interface, and the rest of our app will depend on the interface as opposed to any concrete class.
Defining Attachment#
Below we define Attachment
and use the extends
keyword to extend Unique
and Summary
. This ultimately means that any class that implements Attachment
must also implement Unique
and Summary
:
import Unique from "./Unique";
import Summary from "./Summary";
interface Attachment extends Unique, Summary {
upload(): Promise<boolean>;
}
export default Attachment;
Classes can extend at most one class and implement one or more interfaces. Interfaces can extend one or more interfaces but cannot implement anything. A (child) class extending a (parent) class will result in the child inheriting all of the parent's public and protected properties/methods. A class that implements an interface must implement all methods and properties specified in the interface(s) to avoid compile-time errors. An interface that extends other interfaces results in an interface that "combines" all interfaces, meaning any class that implements an interface must also implement all interfaces that the interface extends.
In addition to extending Unique
and Summary
, attachments must implement an upload()
method that returns a Promise
that resolves to true
if the upload was successful and false
if it was unsuccessful.
A Promise represents a value that will be available at some point in the future. We use the then()
method to access this value as shown below:
// Promise that will resolve to type "string"
const p: Promise<string> = new Promise(resolve => {
setTimeout(() => resolve('banana (1000ms later)'), 1000);
});
// will print 'second' after 1000ms
p.then(val => console.log(val));
// prints 'first' immediately
console.log('apple');
The result of running the code above will be the following:
apple
banana (1000ms later)
We won't be running any "real" asynchronous code, so we'll make use of the Promise.resolve()
function to create promises that immediately resolve to a value (more on that shortly).
Defining the Image#
Below we define an Image
class that implements the Attachment
interface:
import Attachment from "./Attachment";
import { UniqueId } from "./Unique";
import getUniqueId from "../utils/getUniqueId";
class Image implements Attachment {
private format: string;
private url: string;
private title: string;
private id: UniqueId;
constructor(
title: string,
format: string,
url: string,
) {
this.title = title;
this.url = url;
this.format = format;
this.id = getUniqueId();
}
getId(): UniqueId {
return this.id
}
// TODO: implement getSummary()
function getSummary(): string {
return '';
}
This page is a preview of Beginners Guide to TypeScript