Data (Either)
The previous examples of chaining used two implementations of FP: Literal and Empty.
These two classes provide an implementation of Either,
seen in Haskell,
and JavaScript libraries such as
fp-ts,
Folktale,
and more.
Implementations of Either provide a clear and unmistakable difference between the presence and absence of data -
avoiding null, undefined,
and other troublesome ways of representing a lack of data.
Properties
Before getting too far, it may be best to look at the actual properties of Literal and Empty -
the type system will save you from the properties on the backend,
but it may be helpful to see how FP works, and how the objects look after the compiler strips
out type information.
| The following definitions include properties defined in inherited classes to provide
more information that exist in the actual class definitions of  | 
Literalclass Literal<T> extends Data<T> {
  kind: "Literal";
  status: 200 | 201;
  hasData: true;
  hasError: false;
  noValue: false;
  data: T;
}Emptyclass Empty<T = any> extends NoValue<T> {
  kind: "Empty";
  status: 404;
  hasData: false;
  hasError: false;
  noValue: true;
}Using Literal/Empty Values
There are (at least) five different ways to evaluate and process values that are returned
as Literal or Either instances, with reasons why each may be good for certain situations.
We will be using the same data for all of the following examples, which is a basic example of loading a configuration value.
Literal/Empty for use in following examplesimport { readFileSync } from "fs";
function loadPortConfig(filename: string = "port.txt"): Literal<number> | Empty<number> {
  try {
    const fileContent = readFileSync(filename, "utf8");
    const num = parseInt(fileContent, 10);
    if(num && !isNaN(num)) {
      return new Literal(num);
    }
    return new Empty();
  } catch (e) {
    return new Empty();
  }
}
const portConfig = loadPortConfig();Checking 'kind'
Every FP object is required to include a kind field,
which can determine if the returned config is a Literal.
kindvar port: number;
if(portConfig.kind === "Literal") {
  console.log(`Listening on port ${portConfig.data}, as-per config.`);
  port = portConfig.data;
} else {
  console.log("No configured port.  Defaulting to '80'.");
  port = 80;
}Using Description properties (hasData, etc.)
While kind provides an exact match, every FP also contains three flags
providing a more general description of an object:
hasData, hasError, noValue.
This is overkill when only Either or Literal could be returned,
but you could use these flags to filter out errors and empty values:
hasError, noValueif(portConfig.hasError) {
  console.log("Error loading port!");
} else if(portConfig.noValue) {
  console.log("No port specified, will use default.");
} else {
  console.log(`Port configured as ${portConfig.data}`);
}Using status
All FP objects include a status code, intended to represent HTTP response status codes
(or process exit codes).
One could use these fields similar to the descriptor fields - e.g. responses with status in the range 300 - 500 are likely errors, and this could be compared similar to the last example using hasError - although we don’t see why anyone would prefer this.
However, if you are writing general middleware that formats FP objects into HTTP responses,
you may find status useful.
Utility Methods
The above examples used FP properties, but every FP object also includes utility
methods.
The first example used kind to set a default if Empty was found,
however altValue() could avoid the entire if/else block.
altValueconst port = portConfig.altValue(80);