Checkpoint: Session Import

The Course
•
4 min read

Your planner needs to import a saved session. The outside world supplies text; the rest of the application wants a trusted record. Build the boundary between them without any, assertions, or non-null shortcuts.

For this checkpoint Session has topic:string, minutes:number and done:boolean. A topic must be nonblank, minutes finite and nonnegative, and done genuinely boolean. The text “false” is not a boolean and should be rejected. Normalize the topic by trimming it only after confirming it is a string.

The result is either a success containing one clean Session or an error containing a message. Return “Invalid JSON” for syntax failure and “Invalid session” for shape or domain failure. Extra unrelated input fields may be ignored; the returned record should contain the three modeled fields.

Plan three layers: parse text to unknown, inspect the value, construct the output record. Keeping those steps visible makes the contract easier to review and test. This is the same pattern you will expand to a list in the capstone.

Predict, check, then run

Before running, write down the output and explain which information the checker knows. Click Check types first, then Check & run.

Predict, then runTypeScript
const value: unknown = JSON.parse('{"done":false}');

if (typeof value === "object" && value !== null && "done" in value) {
  console.log(typeof value.done);
}

Enable JavaScript to edit and type-check this example.

Check your prediction
boolean

Acceptance cases before you code

Write a small test plan before implementing parse and validate a session. These cases extend the brief; they are not a second worked solution. Predict the expected behavior independently, then test through the public function. A good ordinary example and a good boundary example should catch different possible mistakes.

Case to tryWhat your result should demonstrate
Malformed JSONReport the syntax failure
Valid JSON with text minutesReport the domain failure
Padded topic with numeric zeroReturn normalized typed success without mutation

After the core task passes, deliberately break one rule and identify the case that notices it. Restore the implementation and explain the failure in terms of the contract, not the number of assertions. If a case requires a concept you have not recalled, revisit the relevant lesson before opening the solution.

Your turn

Exercise

Checkpoint: Session Import: practise

Implement parseSession with the contract above. Display Types: 0 min for a valid trimmed topic and zero minutes, Invalid session for text minutes, and Invalid JSON for malformed text. Keep the returned data fully typed.

Your workspaceTypeScript
// Define Session and Result, validate every field, and construct a clean record.

Enable JavaScript to edit and type-check this example.

Hint 1: the idea

The predicate checks must establish every property before you construct Session.

Hint 2: a first step

After rejecting null and non-objects, check each required property with in and typeof.

Show one solution
One possible solutionTypeScript
type Session = {
  topic: string;

  minutes: number;

  done: boolean;
};

type Result =
  | {
      kind: "ok";

      session: Session;
    }
  | {
      kind: "error";

      message: string;
    };

function parseSession(json: string): Result {
  let value: unknown;

  try {
    value = JSON.parse(json);
  } catch {
    return { kind: "error", message: "Invalid JSON" };
  }

  if (
    typeof value !== "object" ||
    value === null ||
    !("topic" in value) ||
    typeof value.topic !== "string" ||
    value.topic.trim() === "" ||
    !("minutes" in value) ||
    typeof value.minutes !== "number" ||
    !Number.isFinite(value.minutes) ||
    value.minutes < 0 ||
    !("done" in value) ||
    typeof value.done !== "boolean"
  ) {
    return { kind: "error", message: "Invalid session" };
  }

  return {
    kind: "ok",
    session: {
      topic: value.topic.trim(),
      minutes: value.minutes,
      done: value.done
    }
  };
}

function display(result: Result): string {
  if (result.kind === "error") {
    return result.message;
  }

  return `${result.session.topic}: ${result.session.minutes} min`;
}

console.log(
  display(parseSession('{"topic":" Types ","minutes":0,"done":false}'))
);
console.log(
  display(parseSession('{"topic":"Types","minutes":"25","done":false}'))
);
console.log(display(parseSession("{")));

Enable JavaScript to edit and type-check this example.

Types: 0 min
Invalid session
Invalid JSON

Explain the types at the function boundary and the runtime checks, if any. Compare your approach before copying this answer.

Change it and explain it

Test every missing field, null, a blank topic, negative minutes and done=“false”. Preserve zero as valid. Finally explain why a successful check of the parser’s source is not enough: its runtime tests must verify that it tells the truth about the input.

Was this article helpful?

Your response is saved on this device.