在没有if
的情况下,是否可以通过never
为undefined
(如Typescript中的assert
)返回的函数调用来限制类型?
示例代码:
interface Foo { bar(): void }
function getFoo(): Foo | undefined { }
function test() {
const foo = someService.getFoo();
assert(foo);
if (!foo) { // now mandatory because without this foo may be still undefined even if assert protects us from this
return;
}
foo.bar(); // , here foo may be undefined
}
我希望能够以这样的方式编写assert
,我可以跳过以下if (!foo)
子句,并将foo
类型限制为普通Foo
。
这在Typescript中可能吗?
我尝试过用never
为抛出以下内容的类型添加重载:
function assertGuard(v: undefined | null | '' | 0 | false): never;
function assertGuard(v: any): void; // i'm not sure which one is captured by TS typesystem here
function assertGuard<T>(v: T | undefined) {
if (v === undefined || v === null || v === '' || v === 0 || v === false) {
throw new AssertionError({message: 'foo'})
}
}
这一个编译,但是对assertGuard(foo)
的调用没有识别出对于undefined
它将返回never
,所以没有将foo
限制为Foo
。
我已经找到了可能的解决方法,但我认为经典的assert
是一种更干净的方法:
function assertResultDefined<T>(v: T|undefined): T | never {
if (v === undefined) {
throw new Error('foo');
}
return v;
}
function die(): never { throw new Error('value expected)}
const foo = assertResultDefined(getFoo()) // foo is Foo, undefined is erased
const foo = getFoo() || die();
// undefined is erased from foo
/ CONS: doesn't play well with types that interpolate to `false` like 0, ''
5条答案
按热度按时间bmp9r5qi1#
typescript 3.7添加了assertions in control flow analysis。
asserts
返回类型 predicate 指示函数仅在Assert成立时返回,否则将引发异常消费者端不再需要黑客。
Playground
此外,可以Assert所提供的参数为所需类型:
Playground
eoxn13cs2#
此https://github.com/Microsoft/TypeScript/issues/8655的 typescript 积压工作中存在问题。因此,目前您无法执行此操作。
你能做的就是使用Assert操作符“!"。在value之后添加!将Assert该值既不是未定义的也不是空的。在你绝对确定它不会导致空或未定义的引用的情况下使用它。
图片来源:https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-type-assertions
vawmfj5a3#
由于
foo
是Foo | undefined
,因此应该以某种方式将其类型更改为Foo
。在上面的代码中,这可以通过以下方式合理地实现:
另一种选择是使用非空Assert(正如另一个答案所建议的):
xbp102n04#
这应该对你有用:
其中
_.isNumber
有一个类型保护x is number
这可以用于任何有类型保护的函数。关键字是您必须重新分配变量,因此
assert
实际上是一个标识函数,它在类型Assert失败时抛出错误ykejflvf5#
具有类型安全的一行程序: