【问题标题】:Typescript: Type Error while using Record type打字稿:使用记录类型时出现类型错误
【发布时间】:2022-01-10 20:12:08
【问题描述】:

对于对象中处理函数的以下代码(请参阅Playground Link),我使用 Record 类型:

interface User {
    id: string;
    avatar: string;
    email: string;
    name: string;
    role?: string;
    [key: string]: any;
}

interface State {
    isInitialized: boolean;
    isAuthenticated: boolean;
    user: User | null;
}

type InitializeAction = {
    type: 'INITIALIZE';
    payload: {
        isAuthenticated: boolean;
        user: User | null;
    };
};

type LoginAction = {
    type: 'LOGIN';
    payload: {
        user: User;
        isAuthenticated: boolean;
    };
};

type LogoutAction = {
    type: 'LOGOUT';
};

type RegisterAction = {
    type: 'REGISTER';
    payload: {
        user: User;
    };
};

type Action =
    | InitializeAction
    | LoginAction
    | LogoutAction
    | RegisterAction;

const handlers: Record<string, (state: State, action: Action) => State> = {
    INITIALIZE: (state: State, action: InitializeAction): State => {
        const {
            isAuthenticated,
            user
        } = action.payload;

        return {
            ...state,
            isAuthenticated,
            isInitialized: true,
            user
        };
    },
    LOGIN: (state: State, action: LoginAction): State => {
        const { user } = action.payload;

        return {
            ...state,
            isAuthenticated: true,
            user
        };
    },
    LOGOUT: (state: State): State => ({
        ...state,
        isAuthenticated: false,
        user: null
    }),
    REGISTER: (state: State, action: RegisterAction): State => {
        const { user } = action.payload;

        return {
            ...state,
            isAuthenticated: true,
            user
        };
    }
};

我确实收到了处理函数的以下错误:

TS2322: Type '(state: State, action: InitializeAction) => State' is not assignable to type '(state: State, action: Action) => State'.   
  Types of parameters 'action' and 'action' are incompatible.     
    Type 'Action' is not assignable to type 'InitializeAction'.       
      Type 'LoginAction' is not assignable to type 'InitializeAction'.         
        Types of property 'type' are incompatible.           
          Type '"LOGIN"' is not assignable to type '"INITIALIZE"'.    

【问题讨论】:

标签: typescript react-typescript


【解决方案1】:

我相信这是因为逆变。 Here 你可以找到关于这个主题的更多信息以及它在 typescript 中的工作原理。

为了输入您的handler 对象,您应该使用mapped types

interface User {
    id: string;
    avatar: string;
    email: string;
    name: string;
    role?: string;
    [key: string]: any;
}

interface State {
    isInitialized: boolean;
    isAuthenticated: boolean;
    user: User | null;
}

type InitializeAction = {
    type: 'INITIALIZE';
    payload: {
        isAuthenticated: boolean;
        user: User | null;
    };
};

type LoginAction = {
    type: 'LOGIN';
    payload: {
        user: User;
        isAuthenticated: boolean;
    };
};

type LogoutAction = {
    type: 'LOGOUT';
};

type RegisterAction = {
    type: 'REGISTER';
    payload: {
        user: User;
    };
};

type Action =
    | InitializeAction
    | LoginAction
    | LogoutAction
    | RegisterAction;


// type Handlers = {
//     INITIALIZE: (state: State, action: InitializeAction) => State;
//     LOGIN: (state: State, action: LoginAction) => State;
//     LOGOUT: (state: State, action: LogoutAction) => State;
//     REGISTER: (state: State, action: RegisterAction) => State;
// }
type Handlers = {
    [Type in Action['type']]: (state: State, action: Extract<Action, { type: Type }>) => State
}


const handlers: Handlers = {
    INITIALIZE: (state, action) => {
        const {
            isAuthenticated,
            user
        } = action.payload;

        return {
            ...state,
            isAuthenticated,
            isInitialized: true,
            user
        };
    },
    LOGIN: (state, action) => {
        const { user } = action.payload;

        return {
            ...state,
            isAuthenticated: true,
            user
        };
    },
    LOGOUT: (state) => ({
        ...state,
        isAuthenticated: false,
        user: null
    }),
    REGISTER: (state, action) => {
        const { user } = action.payload;

        return {
            ...state,
            isAuthenticated: true,
            user
        };
    }
};

Playground

Here你可以找到相关答案。

看这个例子:


type Reducer = (state: State, action: Action) => State;
const reducer: Reducer = (state, action) => state

type ContravariantReducer = Record<string, Reducer>

// Arrow of inheritance has changed in an opposite way
const contravariant: ContravariantReducer = {
    initialize: (state: State, action: InitializeAction) => state
}

// Arrow of inheritance has changed in an opposite way
const contravariant2: Record<string, (state: State, action: InitializeAction) => State> = {
    initialize: (state: State, action: Action) => state
}

附:除了打字稿类型问题,我坚信你应该根据 @Dima Parzhitsky

提供的 redux 文档来输入你的 reducer

【讨论】:

    【解决方案2】:

    这有点脏,但它有效:

    const handlers: Record<string, (state: State, action: Action) => State> = {
        INITIALIZE: (state: State, action: Action): State => {
            const { isAuthenticated, user } = (action as InitializeAction).payload;
    
            return {
                ...state,
                isAuthenticated,
                isInitialized: true,
                user,
            };
        },
        LOGIN: (state: State, action: Action): State => {
            const { user } = (action as LoginAction).payload;
    
            return {
                ...state,
                isAuthenticated: true,
                user,
            };
        },
        LOGOUT: (state: State): State => ({
            ...state,
            isAuthenticated: false,
            user: null,
        }),
        REGISTER: (state: State, action: Action): State => {
            const { user } = (action as RegisterAction).payload;
    
            return {
                ...state,
                isAuthenticated: true,
                user,
            };
        },
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-13
      • 2022-01-19
      • 1970-01-01
      • 2021-06-10
      • 1970-01-01
      • 2018-08-12
      • 2018-12-17
      • 1970-01-01
      相关资源
      最近更新 更多