我有一个具有两个属性的对象:typeposition.type属性的值可以是‘a’或‘b’.如果type为‘a’,则position属性的类型应为"top" | "bottom";如果type为‘b’,则为"left" | "right".

type Height = { type: 'a'; position: 'top' | 'bottom' };
type Width = { type: 'b'; position: 'left' | 'right' };
type MyObject = Height | Width;

export const myObj: MyObject = {
  position: 'right',
  type: 'a',
};

代码本身是正确的,如果值position与值type不兼容,则会显示错误.但是,当我try 访问myObjposition属性时,无论type属性的值是多少,IntelliSense都会向我显示position属性的所有可能选项.

enter image description here

有没有办法确保智能感知只显示与type属性相关的选项?也就是说,当type是‘a’时,IntelliSense应该只显示"top" | "bottom"的选项,而当type是‘b’时,IntelliSense应该只显示"left" | "right"的选项.

推荐答案

这看起来像是TypeScrip的自动建议列表中的错误或限制.正如您所说,只要您指定type,编译器就会清楚地知道哪些值对于position是可接受的:

let myObj1: MyObject;
myObj1 = { type: 'a', position }
//                    ^^^^^^^^ 
// (property) position: "top" | "bottom"

但是你得到的是你的自动建议列表中所有可能的position个值的联合.

myObj1 = { type: 'a', position: "" }
// -----------------------------^
// ?: "bottom"
// ?: "left"
// ?: "right"
// ?: "top"

我找不到关于这一点的现有issue in GitHub;如果有人提交了一个,它可能会要求在输入其判别属性已经输入的discriminated union类型的值时,字符串literal types的自动完成/建议列表应该筛选为适用于相关联盟成员的列表.并为它作为设计限制而被关闭的可能性做好准备;事实证明,修复这个问题将在其他更常见的场景中 destruct 所需的行为.


无论如何,除非这一点改变,否则我只能建议变通办法.一种是使用generic帮助器函数通过判别式缩小输入类型,以便编译器甚至不能使用不适用的字符串文字类型:

const asMyObject = <K extends MyObject['type']>(
  obj: Extract<MyObject, { type: K }>
) => obj;
export const myObj: MyObject = asMyObject({
  type: 'b',
  position: '',
  // -------^
  // ?: "left"
  // ?: "right"
})

如果要这样做,不妨将它们拆分到多个参数中,这样对调用者来说可能更容易:

const asMyObject = <K extends MyObject['type']>(
  ...[type, position]: [
    type: K,
    position: Extract<MyObject, { type: K }>['position']
  ]) => ({ type, position });
  
export const myObj: MyObject =
  asMyObject('b', '');
  // --------------^
  // ?: "left"
  // ?: "right"

这两种方法都不是很好,但至少有可能影响建议列表.

Playground link to code

Typescript相关问答推荐

等待的R没有用响应对象展开到R

TypeScript类型不匹配:在返回类型中处理已经声明的Promise Wrapper

如何在TypeScrip面向对象程序设计中用方法/属性有条件地扩展类

迁移到Reaction路由V6时,获取模块Reaction-Router-Dom';没有导出的成员RouteComponentProps错误

Angular 信号:当输入信号改变值时,S触发取数的正确方式是什么?

在MessageStore对象中实现条件类型时出现TypeScrip错误

在嵌套属性中使用Required

类型脚本中没有接口的中间静态类

为什么在回调函数的参数中不使用类型保护?

角效用函数的类型推断

如何在react组件中使用doctype和html标签?

重载函数的T helper参数

在TypeScript中扩展重载方法时出现问题

react 路由不响应参数

创建一个函数,该函数返回一个行为方式与传入函数相同的函数

字幕子集一个元组的多个元素

为什么`map()`返回类型不能维护与输入相同数量的值?

如何使对象同时具有隐式和显式类型

Typescript:是否将联合类型传递给重载函数?

如何按成员资格排除或 Select 元组?