```ts
function parseSemver(version: string): { major: number; minor: number; patch: number; prerelease: string | null; build: string | null } {
  // Remove leading "v" if present, but ensure the version is a non-empty string after this.
  if (version.startsWith("v")) {
    version = version.slice(1);
  }

  if (!/^[0-9]+(\.[0-9]+)*(-[a-zA-Z0-9-]*)?(\+[0-9A-Za-z0-9-]*)?$/.test(version)) {
    throw new Error(`Invalid format: ${version}`);
  }

  const parts = version.split(/[-+]/);

  const major = parseInt(parts[0], 10);
  const minor = parseInt(parts.length > 1 ? parts[1] : '0', 10);
  const patch = parseInt(parts.length > 2 ? parts[2] : '0', 10);

  let prerelease: string | null = null;
  let build: string | null = null;

  if (parts.length > 3) {
    prerelease = parts.slice(3).join("-");
  }

  if (parts.length > 4) {
    build = parts.slice(4).join("+");
  }

  return { major, minor, patch, prerelease, build };
}
```