typescript - 将类型分配给多个类型

时间:2017-04-11 11:23:12

标签: typescript ngrx

我正在使用nrgx / store并按照示例应用程序使用类来强力键入我的操作,例如

export const ActionTypes ={
    SET_ACTIVE_USER: type('[UserState] Set Active User'),
    SET_USERLIST: type('[UserState] Set Userlist')
};

export class SetActiveUserAction implements Action {
    type = ActionTypes.SET_ACTIVE_USER;
    constructor(public payload:User){}
}

export class SetUserlistAction implements Action {
    type = ActionTypes.SET_USERLIST;
    constructor(public payload:User[]){}
}

export type Actions
    = SetActiveUserAction
    | SetUserlistAction

我现在在我的减速机中遇到了类型问题。由于导出的Actions可以是User或User []类型,它不允许我为其分配用户列表:User [](我想使用像forEach这样的数组方法)

export function reducer(state = INITIAL_STATE, action: userAction.Actions): State {

    switch (action.type) {
        case userAction.ActionTypes.SET_USERLIST: {

            let userlist:User[] = action.payload <-------Type Issue

            return tassign(state, { userlist: action.payload })
        }

        default: {
            return state
        }
    }
}

1 个答案:

答案 0 :(得分:2)

处理此问题的一种方法是强制转换属性,以便TypeScript知道它应该是什么类型。

let userlist:User[] = <User[]>action.payload;

如果这不起作用,那么您可以转换为any,然后转换为该类型。

let userlist:User[] = <User[]><any>action.payload;

但那并没有真正使用类型系统来充分发挥它的潜力,而且代码也不是很好。

如果我们可以告诉类型系统如何确定它是什么类型,那么它不是强制使用类型转换为特定类型,而是很好。

所以......听起来你想要Type Guards。

https://www.typescriptlang.org/docs/handbook/advanced-types.html
(查找标题为&#39;用户定义类型保护&#39;)的部分

您可以创建一个特殊函数来测试某个对象是否属于某种类型 该函数返回一个bool,匹配为true,不匹配为false 在代码中使用该函数测试变量时,TypeScript会识别类型测试并更改该变量的类型以匹配测试类型。

所以你最终会得到这样的代码:

if (isUserAction(action)) {
    let user: IUser = action.Payload;
}

我无法让他们使用您所拥有的确切对象布局,但我做了一个类似的例子,其中包含一些允许类型保护工作的调整。

enum ActionType { User = 1, Users = 2 }
interface IAction { Type: ActionType; }
interface IUser { Name: string; }

class Action<T> implements IAction {
    public Type: ActionType;
    public Payload: T;

    constructor(type: ActionType, payload: T) {
        this.Type = type;
        this.Payload = payload;
    }
}

class UserAction extends Action<IUser> {
    constructor(payload?: IUser) {
        super(ActionType.User, payload);
    }
}

class UsersAction extends Action<IUser[]> {
    constructor(payload?: IUser[]) {
        super(ActionType.Users, payload);
    }
}

function isUserAction(action: IAction): action is UserAction {
    return action.Type === ActionType.User;
}

function isUsersAction(action: IAction): action is UsersAction {
    return action.Type === ActionType.Users;
}

function processAction(action: IAction) {
    if (isUserAction(action)) {
        let user: IUser = action.Payload;
        console.log(`user: ${user.Name}`);
    } else if (isUsersAction(action)) {
        let users: IUser[] = action.Payload;
        for (let user of users) {
            console.log(`users: ${user.Name}`);
        }
    } 
}

processAction(new UserAction({ Name: "foo" }));
processAction(new UsersAction([{ Name: "bar" }, { Name: "baz" }]));

Code @ TypeScript Playground

输出:

user: foo  
users: bar  
users: baz

documentation非常好,并且有很多详细信息可以教你这些功能以及所有其他功能。

另一个好消息来源是basarat.gitbooks.io