Рассмотрим следующий код, который пытается условно добавить свойство к объекту с предполагаемым типом:
const foo = {
a: 1,
b: 2,
};
if (bar) {
foo.c = 3; // Error: Property 'c' does not exist on type '{ a: number; b: number; }'.(2339)
}
Ошибку можно убрать, явно объявив тип foo
как { a: number; b: number; c?: number; }
или используя спред для условного добавления c
:
const foo = {
a: 1,
b: 2,
...(bar ? { c: 3 } : {}),
};
Однако предположим, что мы хотели сохранить исходную структуру кода, но также хотели избежать явного объявления свойств, которые можно вывести. Существуют ли какие-либо решения, которые могли бы удовлетворить оба пункта? Например, можно ли как-то настроить выводимый тип, например:
const foo = {
a: 1,
b: 2,
} as { ...; c?: number; }; // Example, does not work
Это некрасиво, но работает: типы свойств для a
и b
выводятся, и их не нужно объявлять избыточно.
function withMissingProps<T>() {
return function<S>(obj: S): S & Partial<T> {
return obj;
}
}
const foo = withMissingProps<{ c: number }>()({
a: 1,
b: 2
});
if (Math.random() > 0.5) {
foo.c = 1;
}
Есть два параметра типа, T
и S
, для объявленных и предполагаемых свойств соответственно. К сожалению, если функция имеет два параметра типа, вы должны либо указать оба, либо вывести оба; решение состоит в том, чтобы каррировать функцию, хотя это означает дополнительную пару скобок.
Я также нашел этот хак, который, к сожалению, компилируется в Object.assign
и, следовательно, имеет ненулевую стоимость времени выполнения:
const foo = {
a: 1,
b: 2,
...{} as {
c?: number,
},
};