打字稿歧视联盟允许无效状态 [英] Typescript Discriminated Union allows invalid state

查看:83
本文介绍了打字稿歧视联盟允许无效状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Typescript 歧视联盟进行建模异步加载数据时比较常见的情况:

I am trying to use a Typescript Discriminated Union to model a rather common scenario when loading data asynchronously:

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

type State = LoadingState | SuccessState | ErrorState;

根据我的理解,这应该根据类型定义限制允许的值组合.但是,类型系统很乐意接受以下组合:

According to my understanding, this should limit the allowed combinations of values according to the type definitions. However, the type system is happy to accept the following combination:

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

我希望这里有一个错误.我是否缺少某些东西,或者以某种方式滥用了类型定义?

I expect an error here. Is there something I am missing or in some way misusing the type definitions?

推荐答案

这是多余的属性检查对联合体起作用的方式的问题.如果将对象文字分配给联合类型的变量,则如果属性存在于联合成员的任何中,则该属性不会被标记为多余.如果我们不认为多余的属性是一个错误(除了对象文字,它们不被视为错误),则您指定的对象文字可能是LoadingState的实例(将isLoading设置为以及一些多余的属性.

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).

要解决此不良行为,我们可以向LoadingState添加属性,以使您的对象文字与LoadingState

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!"
}

这篇关于打字稿歧视联盟允许无效状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆