```ts
export function parseSemver(version: string): { major: number; minor: number; patch: number; prerelease: string | null; build: string | null } {
    // Helper function to validate a single numeric segment
    const isNumericSegment = (segment: string): boolean => /^[0-9]+$/.test(segment) && !/^0+$/.test(segment);

    // Check if the version starts with 'v'
    if (version.startsWith('v')) {
        version = version.slice(1);
    }

    // Split the version into parts
    const parts = version.split('-');

    // Validate the major, minor, and patch segments
    const [majorStr, minorStr, patchStr] = parts;

    if (!isNumericSegment(majorStr) || !isNumericSegment(minorStr) || !isNumericSegment(patchStr)) {
        throw new Error(`Invalid version: ${version}`);
    }

    // Parse the numeric segments
    const major = parseInt(majorStr, 10);
    const minor = parseInt(minorStr, 10);
    const patch = parseInt(patchStr, 10);

    // Handle optional prerelease and build components
    let prerelease: string | null = null;
    let build: string | null = null;

    if (parts.length > 1) {
        [prerelease] = parts.slice(1).filter(str => /^[a-zA-Z]+$/.test(str));
    }

    if (prerelease && prerelease.includes('+')) {
        throw new Error(`Invalid version: ${version}`);
    } else if (prerelease && !/^[0-9]+\.[0-9]+(\-[0-9a-zA-Z.+-]*)?$/.test(prerelease)) {
        throw new Error(`Invalid prerelease in version: ${version}`);
    }

    if (parts.length > 2) {
        build = parts[2].replace('+', '');
    }

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