我有一个具有两个属性的对象:
type
和 position
。 type
属性的值可以是“a”或“b”。如果position
是'a',"top" | "bottom"
属性应该是type
类型,或者如果"left" | "right"
是'b',则type
类型。
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
的值不兼容,将显示错误。但是,当我尝试访问 position
上的 myObj
属性时,IntelliSense 会向我显示 position
属性的所有可能选项,而不管 type
属性的值如何。
有没有办法确保 IntelliSense 只显示与
type
属性相关的选项?也就是说,当 type
为“a”时,IntelliSense 应仅显示 "top" | "bottom"
的选项,而当 type
为“b”时,IntelliSense 应仅显示 "left" | "right"
的选项。
这看起来像是 TypeScript 自动建议列表中的错误或限制。正如您所说,一旦您指定
position
:,编译器就清楚地知道
type
可以接受哪些值
let myObj1: MyObject;
myObj1 = { type: 'a', position }
// ^^^^^^^^
// (property) position: "top" | "bottom"
但是您会在自动建议列表中获得所有可能的
position
值的并集。
myObj1 = { type: 'a', position: "" }
// -----------------------------^
// 🔧: "bottom"
// 🔧: "left"
// 🔧: "right"
// 🔧: "top"
我无法在 GitHub 中找到关于此的现有issue;如果有人提交了一个,它可能应该要求当输入一个 discriminated union 类型的值时,其判别属性已经被输入,字符串 literal types 的自动完成/建议列表应该被过滤到只适用于相关的那些工会会员。并做好将其作为设计限制关闭的可能性的准备;事实证明,解决这个问题会破坏其他更常见场景中的预期行为。
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"
这两种方式都不好,但至少可以影响建议列表。