类型保护

类型保护允许你使用更小范围下的对象类型。

typeof

TypeScript 熟知 JavaScript 中 instanceoftypeof 运算符的用法。如果你在一个条件块中使用这些,TypeScript 将会推导出在条件块中的的变量类型。如下例所示,TypeScript 将会辨别 string 上是否存在特定的函数,以及是否发生了拼写错误:

  1. function doSome(x: number | string) {
  2. if (typeof x === 'string') {
  3. // 在这个块中,TypeScript 知道 `x` 的类型必须是 `string`
  4. console.log(x.subtr(1)); // Error: 'subtr' 方法并没有存在于 `string` 上
  5. console.log(x.substr(1)); // ok
  6. }
  7. x.substr(1); // Error: 无法保证 `x` 是 `string` 类型
  8. }

instanceof

这有一个关于 classinstanceof 的例子:

  1. class Foo {
  2. foo = 123;
  3. common = '123';
  4. }
  5. class Bar {
  6. bar = 123;
  7. common = '123';
  8. }
  9. function doStuff(arg: Foo | Bar) {
  10. if (arg instanceof Foo) {
  11. console.log(arg.foo); // ok
  12. console.log(arg.bar); // Error
  13. }
  14. if (arg instanceof Bar) {
  15. console.log(arg.foo); // Error
  16. console.log(arg.bar); // ok
  17. }
  18. }
  19. doStuff(new Foo());
  20. doStuff(new Bar());

TypeScript 甚至能够理解 else。当你使用 if 来缩小类型时,TypeScript 知道在其他块中的类型并不是 if 中的类型:

  1. class Foo {
  2. foo = 123;
  3. }
  4. class Bar {
  5. bar = 123;
  6. }
  7. function doStuff(arg: Foo | Bar) {
  8. if (arg instanceof Foo) {
  9. console.log(arg.foo); // ok
  10. console.log(arg.bar); // Error
  11. } else {
  12. // 这个块中,一定是 'Bar'
  13. console.log(arg.foo); // Error
  14. console.log(arg.bar); // ok
  15. }
  16. }
  17. doStuff(new Foo());
  18. doStuff(new Bar());

in

in 操作符可以安全的检查一个对象上是否存在一个属性,它通常也被做为类型保护使用:

  1. interface A {
  2. x: number;
  3. }
  4. interface B {
  5. y: string;
  6. }
  7. function doStuff(q: A | B) {
  8. if ('x' in q) {
  9. // q: A
  10. } else {
  11. // q: B
  12. }
  13. }

字面量类型保护

当你在联合类型使里使用字面量类型时,你可以检查它们是否有区别:

  1. type Foo = {
  2. kind: 'foo'; // 字面量类型
  3. foo: number;
  4. };
  5. type Bar = {
  6. kind: 'bar'; // 字面量类型
  7. bar: number;
  8. };
  9. function doStuff(arg: Foo | Bar) {
  10. if (arg.kind === 'foo') {
  11. console.log(arg.foo); // ok
  12. console.log(arg.bar); // Error
  13. } else {
  14. // 一定是 Bar
  15. console.log(arg.foo); // Error
  16. console.log(arg.bar); // ok
  17. }
  18. }

使用定义的类型保护

JavaScript 并没有内置非常丰富的、运行时的自我检查机制。当你在使用普通的 JavaScript 对象时(使用结构类型,更有益处),你甚至无法访问 instacneoftypeof。在这种情景下,你可以创建用户自定义的类型保护函数,这仅仅是一个返回值为类似于someArgumentName is SomeType 的函数,如下:

  1. // 仅仅是一个 interface
  2. interface Foo {
  3. foo: number;
  4. common: string;
  5. }
  6. interface Bar {
  7. bar: number;
  8. common: string;
  9. }
  10. // 用户自己定义的类型保护!
  11. function isFoo(arg: Foo | Bar): arg is Foo {
  12. return (arg as Foo).foo !== undefined;
  13. }
  14. // 用户自己定义的类型保护使用用例:
  15. function doStuff(arg: Foo | Bar) {
  16. if (isFoo(arg)) {
  17. console.log(arg.foo); // ok
  18. console.log(arg.bar); // Error
  19. } else {
  20. console.log(arg.foo); // Error
  21. console.log(arg.bar); // ok
  22. }
  23. }
  24. doStuff({ foo: 123, common: '123' });
  25. doStuff({ bar: 123, common: '123' });

原文: https://jkchao.github.io/typescript-book-chinese/typings/typeGuard.html