【问题标题】:Typescript type issue in reducer like function减速器类功能中的打字稿类型问题
【发布时间】:2020-10-16 20:37:19
【问题描述】:

我在类似函数的 reducer 中遇到了一些类型错误(我的目标是能够使用我的 state 中的 formData 生成表单)。

但由于减速器函数中的此错误,我正在努力输入表单属性:

  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'
            }
        },
    }
}

【问题讨论】:

    标签: typescript typescript-typings


    【解决方案1】:

    TypeScript 无法确定您从 reducer 的每个分支返回的内容将具有您想要执行的操作的正确形状。你可以帮忙:

    编辑编辑:你必须使用已经通过类型保护的东西(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();
      }
    }
    

    【讨论】:

    • 老实说,虽然您可能希望 Attributes 成为 DecimalAttributesStringAttributes 扩展的接口,但这样您就可以在不具体化联合类型的情况下获得多态性。
    • 好的,谢谢它确实有效我认为检查属性类型(使用类型保护)并拥有值的类型就足够了。不知道我必须投它!谢谢你的回答!
    • 糟糕,您实际上没有。刚刚更新了我的答案,但您只对 attributes 进行了类型保护,而不是 state.formData[action.attributeIdentifier] 所以这里它仍然可以是任一属性类型。
    猜你喜欢
    • 1970-01-01
    • 2019-06-19
    • 2019-04-10
    • 1970-01-01
    • 2019-01-13
    • 2019-02-08
    • 2021-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多