Компилятор не сужает тип необязательного свойства до требуемого при назначении. Это так, как задумано, хотя иногда это расстраивает. См. microsoft / TypeScript # 29827 для некоторого обсуждения. И вообще, записи свойств не сужают тип целого объекта, см. microsoft / TypeScript # 35086 для некоторого обсуждения. Сужение потока управления при назначении происходит только тогда, когда вы присваиваете значение переменной / свойству типа объединения, и это происходит только с конкретной переменной / свойством, которую вы устанавливаете. Все это означает, что obj.id = "21"
не изменяет тип obj
, как видит компилятор.
Самый простой способ справиться с этим - использовать утверждение типа просто сказать компилятору, что вы уверены, что возвращаете правильный тип. Вы знаете, что сделали обязательным свойство id
, поэтому можете просто утверждать, что оно истинно:
function withDefaultId<T extends { id?: string }>(obj: T): T & { id: string } {
if (!obj.id) {
obj.id = "21"
}
return obj as T & { id: string };
}
Менее просто изменить вашу реализацию на форму, которую компилятор уже видит как возвращающую правильный тип , Например, что-то вроде:
function withDefaultId<T extends { id?: string }>(obj: T): T & { id: string } {
return Object.assign(obj, { id: obj.id || "21" });
}
Это должно дать вам аналогичный результат (при условии, что obj
не имеет некоторого динамического c setter для свойства id
, или есть какие-то другие волшебные c странности. Но теперь нет ошибки компилятора.
Хорошо, надеюсь, это поможет; удачи!
Ссылка на игровую площадку с кодом