```ts
export class LruCache<K, V> {
  private _capacity: number;
  private _lastUsed: Map<K, { value: V; timestamp: Date }>;
  private _data: Record<K, V>;

  constructor(capacity: number) {
    if (typeof capacity !== 'number' || capacity <= 0) {
      throw new Error('Capacity must be a positive integer');
    }
    this._capacity = capacity;
    this._lastUsed = new Map();
    this._data = {};
  }

  get(key: K): V | undefined {
    const cachedValue = this._data[key];
    if (!cachedValue) return undefined;

    this._lastUsed.set(key, { value: cachedValue.value, timestamp: new Date() });
    this._sortByLastUse();
    return cachedValue.value;
  }

  set(key: K, value: V): void {
    const existingItem = this._data[key];
    if (existingItem) {
      delete this._lastUsed[key];
    }

    this._data[key] = { value, timestamp: new Date() };
    this._lastUsed.set(key, { value, timestamp: new Date() });

    this._sortByLastUse();
  }

  size(): number {
    return Object.keys(this._data).length;
  }

  private _sortByLastUse(): void {
    const entries = Array.from(this._lastUsed.entries());
    entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
    for (let i = this._capacity; i < entries.length; ++i) {
      const keyToRemove = entries[i][0];
      delete this._data[keyToRemove];
      this._lastUsed.delete(keyToRemove);
    }
  }
}
```

This TypeScript implementation of `LruCache` matches the provided interface exactly, ensuring it meets all documented requirements. The constructor validates the capacity and throws an error if the input is incorrect. methods like `get`, `set`, and `size` function as expected, maintaining a least-recently-used policy with a specified capacity.