Can't narrow simple TypeScript union type with

2019-06-25 12:12发布

I have two unioned types, one has a property and the other one hasn't. I assumed that checking for the existence of that property would allow me to narrow it down, but it isn't working.

I've created this Playground repro. This other very similar thing seems to work just fine. Am I using unions the wrong way?

Here's the code for the sake of completeness:

export interface AuthenticatedProfile {
    readonly userId: string;
    readonly name: string;
}
export interface AnonymousProfile {
    readonly userId: undefined;
    readonly otherProp: string;
}
export type Profile = AnonymousProfile | AuthenticatedProfile;

function handleProfile(prof: Profile) {
    if (prof.userId) {
        console.log(prof.name);
    }
}

Thanks!

2条回答
做自己的国王
2楼-- · 2019-06-25 13:01

You can do the following:

export interface AuthenticatedProfile {
    readonly type: "AuthenticatedProfile";
    readonly userId: string;
    readonly name: string;
}

export interface AnonymousProfile {
    readonly type: "AnonymousProfile";
    readonly userId: undefined;
    readonly otherProp: string;
}

export type Profile = AnonymousProfile | AuthenticatedProfile;

function handleProfile(prof: Profile) {
    if (prof.type === "AnonymousProfile") {
        console.log(prof.name); // Error
        console.log(prof.otherProp); // OK
        console.log(prof.userId); // OK
    }
    if (prof.type === "AuthenticatedProfile") {
        console.log(prof.name); // OK 
        console.log(prof.otherProp); // Error
        console.log(prof.userId); // OK
    }
}
查看更多
爷、活的狠高调
3楼-- · 2019-06-25 13:12

You can use type guards to restrict the type of the prof parameter.

export interface AuthenticatedProfile {
    readonly userId: string;
    readonly name: string;
}
export interface AnonymousProfile {
    readonly userId: undefined;
    readonly otherProp: string;
}
export type Profile = AnonymousProfile | AuthenticatedProfile;

function isAuthenticatedProfile(prof: Profile): prof is AuthenticatedProfile {
    return (<AuthenticatedProfile>prof).name !== undefined;
}

function isAnonymousProfile(prof: Profile): prof is AnonymousProfile {
    return (<AnonymousProfile>prof).otherProp !== undefined;
}

function handleProfile(prof: Profile) {
    if (isAuthenticatedProfile(prof)) {
        console.log(prof.name);
    } else if (isAnonymousProfile(prof)) {
        console.log(prof.otherProp);
    }
}

You can read more about type guards in typescript in the Advanced Types section in the handbook.

查看更多
登录 后发表回答