Typescript Discriminated Union allows invalid state

喜你入骨 提交于 2019-11-26 17:56:07

This is an issue with the way excess property checks work on unions. If an object literal is assigned to a variable of union type, a property will not be marked as excess if it is present on any of the union members. If we don't consider excess properties to be an error (and except for object literals they are not considered an error), the object literal you specified could be an instance of LoadingState (an instance with isLoading set to true as mandated and a couple of excess properties).

To get around this undesired behavior we can add properties to LoadingState to make your object literal incompatible with LoadingState

type LoadingState = { isLoading: true; isSuccess?: never }
type SuccessState = { isLoading: false; isSuccess: true; }
type ErrorState =   { isLoading: false; isSuccess: false; errorMessage: string; }

type State = LoadingState | SuccessState | ErrorState;

const testState: State = { // error
    isLoading: true,
    isSuccess: true,
    errorMessage: "Error!"
}

We could even create a type that would ensure such member will be added

type LoadingState = { isLoading: true; }
type SuccessState = { isLoading: false; isSuccess: true; }
type ErrorState =   { isLoading: false; isSuccess: false; errorMessage: string; }

type UnionKeys<T> = T extends any ? keyof T : never;
type StrictUnionHelper<T, TAll> = T extends any ? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;
type StrictUnion<T> = StrictUnionHelper<T, T>

type State = StrictUnion< LoadingState | SuccessState | ErrorState>

const testState: State = { // error
    isLoading: true,
    isSuccess: true,
    errorMessage: "Error!"
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!