Это, по сути, ограничение дизайна TypeScript , по крайней мере, на данный момент.
Существует только так много, что мы можем ожидать, что компилятор поймет о манипулировании условными типами, которые зависят от универсального типапараметры. Возможно, компилятор может быть специально проверен, чтобы T[T[K] extends U ? K : never]
можно было присвоить U
. Но это будет стоить чего-то с точки зрения сложности проверки типов и времени компиляции, и любая выгода будет видна только некоторой части пользователей, которые специально делают подобные вещи. Это может стоить того, но я не задерживаю дыхание.
Между тем, у вас есть два основных способа с этим справиться. Один: разумное использование утверждения типа , чтобы сказать компилятору, что он не такой умный, как вы:
const functionOnlyForStrings = <T>(obj: T, key: GetNames<T, string>) => {
const t = obj[key] as any as string; // I'm smarter than you, compiler! ?
return t.toUpperCase()
}
Два: пройти компилятор через безопасность типов ситуации с помощьюдавая ему несколько общих типов, которые он правильно проверяет :
const functionOnlyForStrings = <
T extends Record<K, string>, // constrain T to be a function of K
K extends GetNames<T, string> // constrain K to be a function of T
>(obj: T, key: K) => {
const t = obj[key]; // inferred as T[K]
return t.toUpperCase() // no error
}
Это работает, потому что компилятор уже понимает, что {[P in K]: V}[K]
будет назначено на V
, и, таким образом, T[K]
будет назначено на string
.
Надеюсь, что поможет;удачи!
Ссылка на код