#typescript #typescript-typings
#typescript #typescript-типизации
Вопрос:
Я написал функцию в typescript 4.0.5, которая проходит через объект и выполняет заданный обратный вызов для каждого свойства, аналогично array.forEach (см. Ниже). Если noImplicitAny: true
задано в tsconfig, ввод функции, похоже, работает только в том случае, если все свойства имеют один и тот же тип.
export function forEachKey<T extends Object>(obj: T, cb: (key: Extract<keyof T, string>, value: T[keyof T]) => void): void {
for (const k in obj) {
if (Object.prototype.hasOwnProperty.call(obj, k)) {
cb(k, obj[k]);
}
}
}
В следующем примере ошибок нет:
interface TestNumber {
a: number;
b: number;
}
const t1Nr: TestNumber = { a: 1, b: 2 };
const t2Nr: TestNumber = { a: 3, b: 4 };
forEachKey(t1Nr, (key, value) => {
t2Nr[key] = value;
});
Но как только появятся свойства с другим типом:
interface TestMixed {
a: number;
b: string;
}
const t1: TestMixed = { a: 1, b: '2' };
const t2: TestMixed = { a: 1, b: '2' };
forEachKey(t1, (key, value) => {
t2[key] = value; // error
});
Я получаю сообщение об ошибке:
TS2322: Type 'string | number' is not assignable to type 'never'. Type 'string' is not assignable to type 'never'.
Насколько я вижу, мне нужно объявить тип value
as T[key]
, но я не смог найти способ сделать это.
Кто-нибудь знает, как исправить ввод текста? Заранее спасибо
Редактировать:
После того, как ответ Алексея работал с этим простым примером, я попытался преобразовать пример в мою текущую реализацию. Там у нас есть класс, подобный следующему:
class TestMixed2Class implements TestMixed {
constructor (public a: number = 1, public b: string = '2', public c: number = 3) {}
setParams(params: TestMixed) {
forEachKey(params, (key, value) => this[key] = value); // error
}
}
Это приводит к ошибке
TS2322: Type 'TestMixed[K]' is not assignable to type 'this[K]'.
Type 'TestMixed' is not assignable to type 'this'.
'this' could be instantiated with an arbitrary type which could be unrelated to 'TestMixed'.
Type 'TestMixed[K]' is not assignable to type 'never'.
Type 'string | number' is not assignable to type 'never'.
Type 'string' is not assignable to type 'never'.
Есть ли также способ добиться правильного ввода здесь?
Ответ №1:
Вы можете ввести параметр общего типа во внутренней функции for key
, чтобы Typescript мог сопоставлять key
и value
:
function forEachKey<T extends object>(obj: T, cb: <K extends keyof T>(key: K, value: T[K]) => void): void {
for (const k in obj) {
if (Object.prototype.hasOwnProperty.call(obj, k)) {
cb(k, obj[k]);
}
}
}
Комментарии:
1. Спасибо, это работает. К сожалению, у меня возникли еще некоторые проблемы при переводе примера в нашу реализацию (см. Редактирование)