У меня есть универсальная функция для обновления состояния (вариант использования - это динамическая обработка обновлений таблиц в React), и я использовал универсальные методы, чтобы гарантировать, что вызов функции является типобезопасным, но я не понимаю, почему TypeScript не компилируется.
В самой функции кажется, что Typescript не использует всю доступную информацию для сужения типа, а вместо этого думает, что я все еще работаю с полным объединением. Он явно знает достаточно об аргументах, чтобы определить, правильно ли вызывается функция, так почему же он терпит неудачу при проверке типов фактической реализации?
Ошибка на row[field] = value
.
Минимальный пример:
type First = { a: string; b: string; c: string }
type Second = { b: string; c: string; d: string }
type Third = { c: string; d: string; e: string }
type State = {
first: First[]
second: Second[]
third: Third[]
}
const update = <
S extends State,
TK extends keyof State,
T extends S[TK],
R extends T[number],
F extends keyof R
>(
state: State,
tagName: TK,
rowIndex: number,
field: F,
value: R[F]
) => {
// fine
const tag = state[tagName]
// fine
const row = tag[rowIndex]
// keyof typeof row is now 'c'
// TYPE ERROR
row[field] = value
}
const state: State = {
first: [{ a: "", b: "", c: "" }],
second: [{ b: "", c: "", d: "" }],
third: [{ c: "", d: "", e: "" }],
}
// this succeeds as expected
update(state, "first", 0, "a", "new")
// and this fails as expected
// @ts-expect-error
update(state, "second", 0, "a", "new")