присвоение можно запихнуть в функцию-генерик, тогда не будет ругаться:
// ----- общий код с генериками ---------------
type Parsers<T extends object> = Omit<{
[K in keyof T]: (str: string) => T[K];
}, 'id'>;
function setValue<T extends object>(obj: T, key: Exclude<keyof T, 'id'>, value: string, parsers: Parsers<T>): void {
obj[key] = parsers[key](value); // магия
}
// ----- конкретный кейс ---------------------
interface Todo {
id: number;
name: string;
text: string;
complete: boolean;
num: number;
}
type List = 'name' | 'text' | 'complete' | 'num';
let list: List[] = ['name', 'text', 'complete', 'num']
const parsers: Parsers<Todo> = {
complete: s => s === 'true',
name: s => s,
text: s => s,
num: s => +s
};
const data: Todo = {
id: 1,
name: '',
text: '',
complete: false,
num: 0,
}
for(let input of list) {
setValue(data, input, formData[input].value, parsers);
}
здесь конвертации из строки во что-нибудь вынесены в отдельный конфиг parsers. Функция setValue принимает его как параметр, и достает из него необходимый парсер по ключу. По каким именно причинам TS не ругается на строку внутри setValue, сказать трудно. Видимо, из-за неопределенности параметра Т, не к чему придраться )