简体   繁体   English

用 Generics 推断正确的类型

[英]Inferring the correct type with Generics

I'm trying to create a reducer function that allows us to infer the allowed properties and value in a payload, and this currently works, if the type property in the dispatch is changed, it will allow for only the values that are associated with the ToolMap to be passed and will throw errors if wrong name value is passed in payload.我正在尝试创建一个reducer function,它允许我们推断有效负载中允许的属性和值,这目前有效,如果调度中的类型属性发生更改,它将只允许与关联的值要传递的 ToolMap,如果在有效负载中传递了错误的名称值,则会引发错误。

The issue occurs in the receiving end of the reducer, the action.payload can't properly infer that the name property is correct, it always thinks it a union type of either CursorToolName or DrawingToolName .问题发生在reducer的接收端,action.payload无法正确推断出name属性是正确的,它总是认为它是CursorToolNameDrawingToolName的联合类型。 Which makes me a bit confused as when the payload reaches that case in the switch statement it should always be the correct type.这让我有点困惑,因为当负载到达 switch 语句中的那个 case 时,它应该始终是正确的类型。

type ToolCategory = 'CursorTools' | 'DrawingTools'
type CursorToolName = 'Cursor' | 'Measure'
type DrawingToolName = 'Brush' | 'Pencil'


type ToolMap = {
    CursorTools: CursorToolName;
    DrawingTools: DrawingToolName
}

interface ToolState {
    CursorTools: Tool<'CursorTools'>
    DrawingTools: Tool<'DrawingTools'>
}

interface ToolAction<T extends ToolCategory>{
    type: T;
    payload: Tool<T>
}

interface Tool<T extends ToolCategory> {
    name: ToolMap[T];
    onEnter?: () => void;
}

const reducer = <T extends ToolCategory>(
    state: ToolState,
    action: ToolAction<T>
): ToolState => {
    switch(action.type){
        case 'CursorTools': {
            return {
                ...state,
                CursorTools: {
                    // This doesn't infer that the payload.name is of correct type
                    name: action.payload.name
                }
            }
        }
    }

    return state;
}

// This infers the name in the payload we can pass, and we can never pass the wrong value
reducer({CursorTools: {name: 'Cursor'}, DrawingTools: {name: 'Brush'}
}, {type: 'CursorTools', payload: {
    name: 'Cursor'
}})

The following would do the trick:以下方法可以解决问题:

const reducer = <T extends ToolCategory, S extends ToolState>(
    state: S,
    action: ToolAction<T>
): S => {
    switch(action.type){
        case 'CursorTools': {
            return {
                ...state,
                CursorTools: {
                    name: action.payload.name
                }
            }
        }
    }

    return state;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM