减速器中的打字稿类型问题

时间:2020-10-16 20:37:19

标签: typescript typescript-typings

我正在像reducer这样的函数中遇到一些类型错误(我的目标是能够使用状态中的formData生成表单)。

但是由于我的reducer函数中存在此错误,我在如何键入表单属性上苦苦挣扎:

  Index signatures are incompatible.
          Types of property 'initialValues' are incompatible.
            Type 'string' is not assignable to type 'number'.ts(2322)

代码:

type Attribute = StringAttribute | DecimalAttribute;

enum Type {
    DECIMAL = 'decimal',
    STRING = 'string',
}

interface StringAttribute {
    isErrored: boolean;
    isMissingData: boolean;
    initialValues: string;
    values: string;
    attributeDefinition: {
        type: Type.STRING;
        helperText: string;
        label: string;
    }
}

const isStringAttribute = (attribute: Attribute): attribute is StringAttribute => attribute.attributeDefinition.type === Type.STRING;

interface DecimalAttribute {
    isErrored: boolean;
    isMissingData: boolean;
    initialValues: number;
    values: number;
    attributeDefinition: {
        type: Type.DECIMAL;
        helperText: string;
        label: string;
    }
}

const isDecimalAttribute = (attribute: Attribute): attribute is DecimalAttribute => attribute.attributeDefinition.type === Type.DECIMAL;

type Action =
| { type: 'updateStringValue', attributeIdentifier: string; value: string }
| { type: 'updateDecimalValue', attributeIdentifier: string; value: number }

interface State {
    formData: Record<string, Attribute>
}

const reducer = (state: State, action: Action): State => {
    switch (action.type) {
        case 'updateDecimalValue': {
            const attribute = state.formData[action.attributeIdentifier];
            if (isDecimalAttribute(attribute)) {
                return {
                    ...state,
                    formData: {
                        ...state.formData,
                        [action.attributeIdentifier]: {
                            ...state.formData[action.attributeIdentifier],
                            values: action.value
                        }
                    }
                }
            }

            return state;
        }
    }
}

const initialState: State = {
    formData: {
        stringAttributeIdentifier: {
            isErrored: false,
            isMissingData: false,
            values: 'String data',
            initialValues: 'String data',
            attributeDefinition: {
                type: Type.STRING,
                helperText: 'Some Helper Text',
                label: 'My Attribute Label'
            }
        },
        decimalAttributeIdentifier: {
            isErrored: false,
            isMissingData: false,
            values: 13.32,
            initialValues: 13.32,
            attributeDefinition: {
                type: Type.DECIMAL,
                helperText: 'Some Helper Text',
                label: 'My Attribute Label'
            }
        },
    }
}

1 个答案:

答案 0 :(得分:1)

TypeScript不能使您从化简器的每个分支返回的内容具有想要执行的操作的正确形状。您可以提供帮助:

编辑编辑:您必须使用已经通过类型保护的东西(attributes):

const reducer = (state: State, action: Action): State => {
  switch (action.type) {
    case 'updateDecimalValue': {
      const attribute = state.formData[action.attributeIdentifier];
      if (isDecimalAttribute(attribute)) {
        return {
          ...state,
          formData: {
            ...state.formData,
            [action.attributeIdentifier]: {
              ...attribute,     // <---- THIS THING HAS PASSED THE TYPE GUARD
              values: action.value
            }
          }
        }
      }

      return state;
    }
    case "updateStringValue": {
      const attribute = state.formData[action.attributeIdentifier];
      if (isStringAttribute(attribute)) {
        return {
          ...state,
          formData: {
            ...state.formData,
            [action.attributeIdentifier]: {
              ...state.formData[action.attributeIdentifier], // <---- ERROR: THIS HASN'T
              values: action.value
            }    
          }
        }
      }
      return state;
    }
    default: throw new Error();
  }
}