能否用TypeScript定义可选但不可为undefined的属性?
如何定义可选但存在时不能为
undefined的属性? 概述
我希望禁止任何显式的undefined值,但仍允许隐式的undefined值。
背景
在JavaScript中,访问不存在的键会返回undefined,而访问存在的键也可能返回undefined。例如:
[1, 2, undefined, 4][2]->undefined(显式)[1, 2, 3, 4][99]->undefined(隐式){a: 1, b: undefined}.b->undefined(显式){a: 1, b: 2}.foo->undefined(隐式)
其中示例1和3是访问显式为undefined的值,示例2和4是访问隐式为undefined的值。
问题
我想要定义一个可能存在也可能不存在(可选)的键,但如果它存在,则不能为undefined。这是否可行?
更多细节
我需要定义这样的类型:
// - mustExistAndCouldBeUndefined 必须存在于该类型中,但可以是undefined。 // - couldExistAndCouldBeUndefined 可能存在于该类型中。如果存在,可以是undefined;如果不存在,则为undefined。 // - couldExistButCannotBeUndefinedIfItDoes 可能存在于该类型中。如果存在,不能是undefined;如果不存在,则为undefined。 type Example = { mustExistAndCouldBeUndefined: number | undefined; couldExistAndCouldBeUndefined?: number; ??? couldExistButCannotBeUndefinedIfItDoes ??? }; // 期望合法:couldExistButCannotBeUndefinedIfItDoes不存在(隐式undefined) const a: Example = { mustExistAndCouldBeUndefined: undefined, }; // 期望非法:couldExistButCannotBeUndefinedIfItDoes存在但为undefined(显式undefined) const b: Example = { mustExistAndCouldBeUndefined: undefined, couldExistButCannotBeUndefinedIfItDoes: undefined, };
能否创建出如上代码中couldExistButCannotBeUndefinedIfItDoes这样的属性定义?
解决方案
可以通过联合类型实现这个需求,把类型拆分为「包含该属性且值为非undefined类型」和「不包含该属性」的两种情况的联合:
type Example = | { mustExistAndCouldBeUndefined: number | undefined; couldExistAndCouldBeUndefined?: number; couldExistButCannotBeUndefinedIfItDoes: number; } | { mustExistAndCouldBeUndefined: number | undefined; couldExistAndCouldBeUndefined?: number; couldExistButCannotBeUndefinedIfItDoes?: never; // 用never禁止显式赋值undefined }; // 合法 const a: Example = { mustExistAndCouldBeUndefined: undefined, }; // 非法(符合预期) const b: Example = { mustExistAndCouldBeUndefined: undefined, couldExistButCannotBeUndefinedIfItDoes: undefined, }; // 合法:存在该属性且值为number const c: Example = { mustExistAndCouldBeUndefined: undefined, couldExistButCannotBeUndefinedIfItDoes: 123, };
如果不想重复编写公共属性,可以用工具类型简化:
// 提取公共属性 type BaseExample = { mustExistAndCouldBeUndefined: number | undefined; couldExistAndCouldBeUndefined?: number; }; // 包含目标属性的情况 type ExampleWithRequiredProp = BaseExample & { couldExistButCannotBeUndefinedIfItDoes: number; }; // 不包含目标属性的情况(禁止显式赋值undefined) type ExampleWithoutProp = BaseExample & { couldExistButCannotBeUndefinedIfItDoes?: never; }; // 最终联合类型 type Example = ExampleWithRequiredProp | ExampleWithoutProp;
原理说明
- 当类型为
ExampleWithoutProp时,couldExistButCannotBeUndefinedIfItDoes被定义为?: never:- 允许不写这个属性,符合「可选」的要求
- 如果强制写这个属性,只能赋值
never类型的值,而undefined不属于never,因此会触发类型错误,从而禁止显式赋值undefined
- 联合类型覆盖了「存在属性且值为number」和「不存在属性」两种合法场景,同时排除了「存在属性但值为undefined」的非法场景。
内容的提问来源于stack exchange,提问作者nullromo
相关产品推荐
相关产品推荐

