```ts
export function mergeThreeWay(base: Record<string, string>, ours: Record<string, string>, theirs: Record<string, string>): { merged: Record<string, string>; conflicts: string[] } {
  // Validate inputs
  if (typeof base !== 'object' || typeof ours !== 'object' || typeof theirs !== 'object') {
    throw new Error('All arguments must be objects');
  }

  const merged: Record<string, string> = {};
  const conflicts: string[] = [];

  // Get all unique keys from base, ours, and theirs
  const allKeys = new Set([...Object.keys(base), ...Object.keys(ours), ...Object.keys(theirs)]);

  for (const key of Array.from(allKeys).sort()) {
    const baseValue = base[key];
    const ourValue = ours[key];
    const theirValue = theirs[key];

    if (ourValue === undefined && theirValue === undefined) {
      // Key not present in either ours or theirs, keep base value if any
      if (baseValue !== undefined) {
        merged[key] = baseValue;
      }
    } else if (ourValue === undefined) {
      // Key only in theirs
      if (theirValue === baseValue) {
        // No conflict, take their value
        merged[key] = theirValue;
      } else {
        // Conflict, keep base value
        conflicts.push(key);
      }
    } else if (theirValue === undefined) {
      // Key only in ours
      if (ourValue === baseValue) {
        // No conflict, take our value
        merged[key] = ourValue;
      } else {
        // Conflict, keep base value
        conflicts.push(key);
      }
    } else if (ourValue === theirValue) {
      // Both sides have the same value, no conflict
      merged[key] = ourValue;
    } else {
      // Different values in ours and theirs, conflict
      conflicts.push(key);
      if (baseValue !== undefined) {
        merged[key] = baseValue;
      }
    }
  }

  return { merged, conflicts };
}
```