Оператор спреда небезопасен - PullRequest
0 голосов
/ 01 декабря 2019

У меня есть функция, которая должна возвращать некоторый тип, но использование оператора распространения заставило ее назначить ключ с ошибкой.

interface State {
    fieldA: number,
    fieldB: string
}

const reducer: (state: State, action: {payload: string}) => State = (state, action) => {

    // please note that those variables are not desired
    const tmp = { ...state, feildB: action.payload }; // No compile time error, as I would expect

    // This is too verbose... but works as expected
    const tmp2 = Object.assign<State, Partial<State>>(state, {feildB: action.payload}) // ERROR - this is what I need
    return tmp
}
const t = reducer({fieldA: 1, fieldB: 'OK'}, {payload: 'Misspelled'}) // Misspelled
console.log("feildB", (t as any).feildB) // Misspelled
console.log("fieldB", (t as any).fieldB) // OK

Есть ли способ сделать его безопасным, сохраняя при этом шаблонминимум?

Код детской площадки ЗДЕСЬ

1 Ответ

6 голосов
/ 01 декабря 2019

TypeScript делает то, что должен делать. В вашем случае вы создаете новый объект tmp с новым типом, который имеет 3 поля, а именно:

interface State {
    fieldA: number,
    fieldB: string
}
interface Tmp {
    fieldA: string;
    fieldB: string;
    feildB: string;
}

Другими словами, оператор распространения выполняет следующую операцию:

interface Obj {
    [key: string]: any;
}

const spread = (...objects: Obj[]) => {
    const merged: Obj = {};

    objects.forEach(obj => {
        Object.keys(obj).forEach(k => merged[k] = obj[k]);
    });

    return merged;
}

Оператор распространения создает новый тип объекта для вас;если вы хотите вывести тип, то вы должны сделать:

// this now throws an error
const tmp: State = { ...state, feildB: action.payload };
...