Typescript union type not working

2020-06-15 18:06发布

I have the following classes:

export interface ISimpleUser {
    id: number;
    full_name: string;
}


export interface IMember extends ng.resource.IResource<IMember> {
    id: number;
    project: number;
    user: number|ISimpleUser;
    skills: ISkill[];
    about: string;
    accepted: Boolean;

    updated: Date;
    created: Date;
}

At some point I want to iterate over an arroy of members like in the following example:

        return angular.forEach<resources.IMember>(this.project.members,
            (member: resources.IMember) => {
                return member.user.id == user.id;
            }).length > 0;

But I get this error:

error TS2339: Property 'id' does not exist on type 'number | ISimpleUser'

Don't know what is wrong exactly. I see other parts of the code working with the union types.

Thanks.

3条回答
等我变得足够好
2楼-- · 2020-06-15 18:07

The number type in TypeScript (and JavaScript) doesn't have an id property. To use a property on a union type without protective type checking (to bust the union type), the properties must have the same name and type. For example if the user property were defined like this:

user: IOtherThing|ISimpleUser;

and IOtherThing had an id property, then it would work.

I am guessing, but you probably will have to do something like this:

var getId = (id: number | IMember) => {
        if (typeof id === "number") {
            return id;
        } else {
            return id.id;
        }
    };
return angular.forEach<resources.IMember>(this.project.members,
    (member: resources.IMember) => {
        return getId(member.user.id) === getId(user);
    }).length > 0;
查看更多
Summer. ? 凉城
3楼-- · 2020-06-15 18:18

Typescript doesn't know how to deal with member.user in your foreach, you need to put the logic in a typeof if statement:

return angular.forEach<resources.IMember>(this.project.members, (member: resources.IMember) => {
    var memberUser = member.user;

    if(typeof memberUser === 'number'){
        return memberUser === user.id;
    } else if (typeof member.user === 'object') {
        return memberUser.id === user.id;
    }
}).length > 0;

By using the typeof TypeScript can infer which type you want to use at which point.

Alternatively if you know your list only contains ISimpleUser, then you could cast the member.user i.e var memberUser = <ISimpleUser> member.user;

查看更多
4楼-- · 2020-06-15 18:29

You will need to do some type checking and casting to handle this scenario:

(member: resources.IMember) => {
  return member.user.id == user.id;
  if (typeof (member.user) === 'number') {
    return member.user == user.id;
  } else {
    return (<ISimpleUser>member.user).id == user.id;
  }
}).length > 0;

Just because you know the possible types at code/design time does not mean that the compiles code knows types at run time. So you can check the type of member.user to see if it is a number then conditionally do your comparison.

查看更多
登录 后发表回答