typescript 联合类型无法正确约束对象?

声明了这样一个类型

type MyType = string | {
  StartType?: string;
  StartContext?: string;
  StartDate?: string;
  StartFalg?: string;
} | {
  EndType?: string;
  EndContext?: string;
  EndDate?: string;
  EndFalg?: string;
}

为什么对于这样的变量初始化,并没有提示错误?

const x: MyType = {
  StartDate: '1',
  EndDate: '2'
}

在我理解中, 对象中存在StartDate之后, 这个类型应该就塌缩为

{
  StartType?: string;
  StartContext?: string;
  StartDate?: string;
  StartFalg?: string;
}

此时若存在 EndDate ,应该是有问题的。

请问这种情况是什么原因导致的? 以及如何实现上述逻辑。

阅读 2.5k
2 个回答
✓ 已被采纳

原因是因为你的两个对象字面量里的类型全是可选属性,TS会自动给可选属性添加undefined类型,因此你的声明等价于

type MyType = string | {
  StartType?: string | undefined;
  StartContext?: string | undefined;
  StartDate?: string | undefined;
  StartFalg?: string | undefined;
} | {
  EndType?: string | undefined;
  EndContext?: string | undefined;
  EndDate?: string | undefined;
  EndFalg?: string | undefined;
}

你的这个类型也就满足了TS中弱类型的概念

弱类型(Weak Type)是TypeScript 2.4版本中引入的一个概念。弱类型指的是同时满足以下条件的对象类型:

对象类型中至少包含一个属性。
对象类型中所有属性都是可选属性。
对象类型中不包含字符串索引签名、数值索引签名、调用签名和构造签名。

所以你这种使用方式本身存在问题,和下面这样没有任何区别

type myType = {
    StartType?: string;
    StartContext?: string;
    StartDate?: string;
    StartFalg?: string;
    EndType?: string;
    EndContext?: string;
    EndDate?: string;
    EndFalg?: string;
};

正确的做法应该是你的两个类型都需要有个非可选属性,才能保证你的类型是独立的。

type startType = {
    StartType: string;
    StartContext?: string;
    StartDate?: string;
    StartFalg?: string;
};

type endType = {
    EndType: string;
    EndContext?: string;
    EndDate?: string;
    EndFalg?: string;
};

官方给出的推荐做法:

  1. 仅声明那些确定存在的属性。
  2. 给弱类型添加索引签名(如:[propName: string]: {})
  3. 使用类型断言(如:opts as Options)

你可尝试添加一个变量来做类型收窄

image.png

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题