Как сделать все поля в interface не обязательными без использования знака вопроса в TypeScript

Ответ

Используйте утилитарный тип Partial<T>, который делает все свойства интерфейса необязательными:

interface User {
  name: string;
  age: number;
}

type PartialUser = Partial<User>;
// Эквивалентно:
// type PartialUser = {
//   name?: string;
//   age?: number;
// }

Пример использования:

const user: PartialUser = {}; // Корректно, все поля необязательны

Partial работает рекурсивно только на первом уровне вложенности. Для глубокого Partial используйте кастомные типы или библиотеки типа type-fest.

Ответ 18+ 🔞

Ага, слушай, вот есть у тебя интерфейс, ну, обычный такой, с кучей полей. И ты такой: "Бля, а вдруг мне нужно не всё сразу заполнять, а по кусочкам?". Ну, например, обновление профиля, где меняешь только имя, а возраст — похуй.

Вот для этого и придумали Partial<T>. Эта штука берёт твой строгий интерфейс и делает все его поля необязательными. То есть, по сути, ставит вопросительные знаки на каждом свойстве. Ёпта, красота же!

interface User {
  name: string;
  age: number;
}

// Вжух, и получаем тип, где можно всё, а можно ничего!
type PartialUser = Partial<User>;
// Теперь это как будто:
// {
//   name?: string;
//   age?: number;
// }

И используешь это дело вот так, без всякого стеснения:

const emptyUser: PartialUser = {}; // Всё чисто, ни одного поля!
const onlyName: PartialUser = { name: "Васян" }; // Возраст? Да похуй!

Но, предупреждаю сразу, чтобы потом не было: "Ой, бля, а почему вложенный объект не опциональный?". Partial работает только на первом уровне, поверхностно. Если у тебя внутри ещё объекты — их он не трогает, хитрая жопа.

Для глубокого превращения всего и вся в необязательное, надо либо свои костыли-типы городить, либо использовать библиотеки, вроде type-fest. Там есть PartialDeep и прочие ништяки. Но это уже, как говорится, совсем другая история, ебать мои старые костыли.