Typescript 类断言类型保护 [英] Typescript assert-like type guard
问题描述
这是否可以通过never
返回的函数调用限制类型而没有if
,例如undefined
,如assert
> 在打字稿中?
Is this possible to have types restricted without if
by function calls that never
return for e.g undefined
like assert
in Typescript?
示例代码:
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
.
I would like to be able to write assert
in such way that i can skip following if (!foo)
clause and have foo
type restricted to plain Foo
.
这在 Typescript 中可行吗?
Is this possible in Typescript?
我已经尝试使用 never
为抛出的类型添加重载:
I've tried adding overloads with never
for types that throw:
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
.
This one compiles, but call to assertGuard(foo)
doesn't recognize that for undefined
it will return never
so doesn't restrict foo
to Foo
.
我找到了可能的解决方法,但我认为经典的 assert
是一种更简洁的方法:
I've found possible workarounds but i consider classical assert
a cleaner approach:
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, ''
推荐答案
Typescript 3.7 添加了 断言控制流量分析.
Typescript 3.7 adds assertions in control flow analysis.
asserts
返回类型谓词表示函数仅在断言成立时返回,否则会引发异常
An
asserts
return type predicate indicates that the function returns only when the assertion holds and otherwise throws an exception
不再需要消费者方面的黑客攻击.
Hacks on consumer side are not needed anymore.
interface Foo { bar(): void }
declare function getFoo(): Foo | undefined;
function assert(value: unknown): asserts value {
if (value === undefined) {
throw new Error('value must be defined');
}
}
function test() {
const foo = getFoo();
// foo is Foo | undefined here
assert(foo);
// foo narrowed to Foo
foo.bar();
}
另外可以断言提供的参数是必需的类型:
Additionally one can assert that provided parameter is of required type:
declare function assertIsArrayOfStrings(obj: unknown): asserts obj is string[];
function foo(x: unknown) {
assertIsArrayOfStrings(x);
return x[0].length; // x has type string[] here
}
这篇关于Typescript 类断言类型保护的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!