Использование типов утилит для удаления полей объектов

#typescript

Вопрос:

Я использую Omit тип утилиты для удаления description in TodoPreview , но при назначении переменной типа TodoPreview другому типу Todo пропущенное поле все еще присутствует и не попадает во время компиляции. Есть ли способ избавиться от пропущенного поля только в todo2:TodoPreview объявлении типа?

 interface Todo {
  title: string;
  description: string;
  completed: boolean;
  createdAt: number;
}

type TodoPreview = Omit<Todo, "description">;

const todo: Todo = {
  title: "Clean room",
  completed: false,
  createdAt: 1615544252770,
  description: "Test",
};

const todo2: TodoPreview = {
  ...todo
}

//Same result with `const todo2: TodoPreview = todo;`

console.log(todo2);
 

Поскольку это невозможно перехватить во время компиляции, при description наличии поля будет получен следующий результат:

 {
  "title": "Clean room",
  "completed": false,
  "createdAt": 1615544252770,
  "description": "Test"
} 
 

Ответ №1:

Это ожидаемое поведение, поскольку объекты в typescript считаются несколько открытыми для расширения с дополнительными полями. Единственные места, где дополнительные поля могут сделать типы несовместимыми, — это те, где происходит проверка избыточных свойств. И ваше дело не из их числа.

Хотя вы не можете назначить объектный литерал extra полям, вы можете свободно назначить то же значение, которое ранее было присвоено переменной

 type A = {
    s: string
}

const bad: A = { s: '', n: 2 } // excess property check

let _good = { s: '', n: 2}
const good: A = _good // no error 

 

ссылка на игровую площадку

Чтобы явно запретить description поле в исходном объекте, необходимо сделать тип description поля явно не назначаемым:

 type TodoPreview = Omit<Todo, "description"> amp; { description?: never };
 

ссылка на игровую площадку