如何解决Typescript条件为空
我想创建一个函数,该函数接受一个通常是对象但可能为null / undefined的参数,并在非null时有条件返回该类型,否则返回null。
function objOrNull<T>(t: T): T extends null ? null: T {
if (t == null) return null;
return t;
}
此函数签名似乎是正确的,我可以使用objOrNull({})
,objOrNull({a:42})
,objOrNull(null)
,objOrNull(undefined)
进行调用,并且返回的变量具有预期的类型。
但是函数体无法编译,因为return null
和return t
都不能分配给声明的返回类型。
如果我将返回类型声明为T | null
,则函数会编译,但是每当我调用它时,返回的类型都可能为null,这显然不是我想要的-应该可以在运行时确定是否t
为null,返回值也为null,否则不是吗?
添加as any
或类似的丑陋类型转换的简短之处,是否存在“正确”的方法来实现这种功能?对于值,等于条件类型extends null ?
的值是什么?为什么== null
不告诉编译器我处于T extends null
状态?
(我最初的用例是一个接受一个对象或null的函数,如果该对象为null,则返回null,否则返回该对象的一个变体,其中添加了一些属性并删除了一些属性,但将问题归结为我的核心题。) 我原来的用例
解决方法
这基本上是TypeScript中的当前设计限制。编译器不会使用control flow analysis来缩小未指定的通用类型参数的类型(例如函数实现中的T
),也不会使用它来缩小值取决于此类类型参数(例如函数实现中的t
)。
这意味着编译器无法验证可将值分配给诸如T extends undefined ? null : T
之类的条件类型。即使您选中(typeof t === "undefined")
,对于通常将t
从诸如string | undefined
的具体范围缩小到undefined
的控制流分析,对于诸如{{1 }}。即使确实将T
的范围从t
缩小为T
,它也不会将T & undefined
缩小为T
,这是编译器必须意识到undefined
可分配给null
的情况。
在microsoft/TypeScript#33912处存在一个规范的问题,要求某种方式使编译器使用控制流分析来验证返回值对通用条件类型的可分配性。但是我不知道是否或何时解决该问题(尽管这至少是一个由TS团队的核心成员之一提议的好信号)。
这意味着您现在可以做的最好的事情就是使用type assertion(您称其为“丑陋的演员”):
T extends undefined ? null : T
或道德上的等价物,如单个呼叫签名overload:
function objOrNull<T>(t: T): T extends undefined ? null : T {
return (typeof t === "undefined") ? null : t as any;
}
该重载不需要您使用类型声明,但是以与使用类型声明类似的方式是不安全的。意思是:尽管实际上不是在 verify 安全,但是这两种方法都应该可以使编译器平静下来。这是您的工作,因为编译器无法执行:
function objOrNull<T>(t: T): T extends undefined ? null : T;
function objOrNull<T>(t: T): T | null {
return (typeof t === "undefined") ? null : t;
}
或
function badObjOrNull<T>(t: T): T extends undefined ? null : T {
return (typeof t !== "undefined") ? null : t as any; // oops
}
但是,假设您正确实现了它,则它仍然应该可以像调用方所期望的那样运行:
function badObjOrNull<T>(t: T): T extends undefined ? null : T;
function badObjOrNull<T>(t: T): T | null {
return (typeof t !== "undefined") ? null : t; // oops
}
,
您可以使用重载获得相同的结果
function objOrNull(t:null|undefined):null
function objOrNull<T>(t: T):T
function objOrNull<T>(t: T|null):T|null {
return t == null ? null : t;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。