TypeScript入门之类型推断、类型断言、双重断言、非空断言、确定赋值断言、类型守卫、类型别名

简介: TypeScript学习过程中经常会看到类型推断、类型断言、双重断言、非空断言、确定赋值断言、类型守卫、类型别名,这几个概念到底表示啥呢?你真的搞清楚了吗?今天我们就来盘一盘它,帮你一次性弄懂。

类型推断

类型推断就是TypeScript会根据上下文自动帮我们推算出变量或方法的类型,而不需要我们显示去定义。

let str = "this is string";
let num = 123;
let bool = true;
  
// 如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 `any` 类型而完全不被类型检查
let flag; //推断为any
let count = 123; //为number类型
let hello = "hello"; //为string类型

// 根据参数的类型,推断出返回值的类型也是 number
function add(a: number, b: number) { return a + b; }

TypeScript 中,具有初始化值的变量、有默认值的函数参数、函数返回的类型都可以根据上下文推断出来。

有了类型推断,就不需要我们每个变量每个方法都去定义类型,大大提高了我们的开发效率。

类型断言

有些情况下 TS 并不能正确或者准确得推断类型,这个时候可能产生不必要的警告或者报错。

比如初学者经常会遇到的一类问题:

const person = {};

person.name = 'randy'; // Error: 'name' 属性不存在于 ‘{}’
person.age = 20; // Error: 'age' 属性不存在于 ‘{}’

这个时候该怎么办?由于类型推断,这个时候 person 的类型就是 {},根本不存在后添加的那些属性,虽然这个写法在js中完全没问题,但是开发者知道这个 person 实际是有属性的,只是一开始没有声明而已,但是 typescript 不知道啊,所以就需要类型断言了:

interface Person {
  name: string;
  age: number;
}

const person = {} as Person;

person.name = 'randy';
person.age = 20;

但是类型断言不要滥用,在万不得已的情况下使用要谨慎,因为你强制把某类型断言会造成 TypeScript 丧失代码提示的能力。

上面我们使用的是as语法,其实我们还可以使用<>

// 尖括号 语法
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;

// as 语法
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

as<>都可以用来类型推断,但是尖括号格式会与 reactJSX 产生语法冲突,因此我们更推荐使用 as 语法。

双重断言

虽然类型断言是有强制性的,但并不是万能的,因为一些情况下也会失效:

interface Person {
  name: string;
  age: number;
}

const person = 'randy' as Person; // Error

这个时候会报错,很显然不能把 string 强制断言为一个接口 Person,但是并非没有办法,此时可以使用双重断言:

interface Person {
  name: string;
  age: number;
}

const person = 'randy' as any as Person; // ok

先把类型断言为 any 再接着断言为你想断言的类型就能实现双重断言,当然上面的例子肯定说不通的,双重断言我们也更不建议滥用,但是在一些少见的场景下也有用武之地,当你遇到事记得有双重断言这个操作即可。

非空断言

非空断言用!表示,它用来断定某变量一定不是 nullundefined

在上下文中当类型检查器无法断定类型时,一个新的后缀表达式操作符 ! 可以用于断言操作对象是非 null 和非 undefined 类型。

具体而言,x! 将从 x 值域中排除 null 和 undefined,也就是说它断定某变量一定不是 nullundefined

let flag: null | undefined | string;
flag!.toString(); // ok
flag.toString(); // error

确定赋值断言

允许在实例属性和变量声明后面放置一个 ! 号,从而告诉 TypeScript 该属性会被明确地赋值。为了更好地理解它的作用,我们来看个具体的例子:

let x: number;
initialize();

// Variable 'x' is used before being assigned.(2454)
console.log(2 * x); // Error

function initialize() {
  x = 10;
}

很明显该异常信息是说变量 x 在赋值前被使用了,要解决该问题,我们可以使用确定赋值断言:

let x!: number;
initialize();
console.log(2 * x); // Ok

function initialize() {
  x = 10;
}

通过 let x!: number; 确定赋值断言,TypeScript 编译器就会知道该属性会被明确地赋值。

类型守卫

类型守卫说白了就是缩小类型的范围,常用的有typeof、instanceof、in

typeof

通过typeof精细化数据类型进行操作,避免了不必要的错误。

function double(input: string | number | boolean) {
  if (typeof input === "string") {
    return input + input;
  } else {
    if (typeof input === "number") {
      return input * 2;
    } else {
      return !input;
    }
  }
}

instanceof

instanceof 类型保护是通过构造函数来细化类型的一种方式.

class Person3 {
  name = "randy";
  age = 24;
}

class Animal3 {
  name = "dog";
  color = "green";
}

function getSometing(arg: Person3 | Animal3) {
  // 不类型守卫 不管使用啥属性都报错。
  console.log(arg.age); // Error
  console.log(arg.color); // Error

  // 类型细化为 Person
  if (arg instanceof Person3) {
    console.log(arg.color); // Error,因为arg被细化为Person,而Person上不存在 color属性
    console.log(arg.age); // ok
  }
  // 类型细化为 Person
  if (arg instanceof Animal3) {
    console.log(arg.age); // Error,因为arg被细化为Animal,而Animal上不存在 age 属性
    console.log(arg.color); // ok
  }
}

in

跟上面的例子类似,x in y 表示 x 属性在 y 中存在。

class Person4 {
  name = "randy";
  age = 24;
}

class Animal4 {
  name = "dog";
  color = "green";
}

function getSometing(arg: Person4 | Animal4) {
  // 不类型守卫 不管使用啥属性都报错。
  console.log(arg.age); // Error
  console.log(arg.color); // Error

  if ("age" in arg) {
    console.log(arg.color); // Error
    console.log(arg.age); // ok
  }
  if ("color" in arg) {
    console.log(arg.age); // Error
    console.log(arg.color); // ok
  }
}

类型别名

类型别名会给一个类型起个新名字,单不是创建一个新类型。类型别名有时和接口很像,但是可以作用于原始值、联合类型、元组以及其它任何你需要手写的类型.

你可以使用 type SomeName = someValidTypeAnnotation的语法来创建类型别名:

type some = boolean | string

const b: some = true // ok
const c: some = 'hello' // ok
const d: some = 123 // 不能将类型“123”分配给类型“some”

类型别名可以给已有类型取别名:

type newstring = string

const str: newstring = 'randy'

此外类型别名可以是泛型:

type Container<T> = { value: T };

也可以使用类型别名来在属性里引用自己:

type Tree<T> = {
  value: T;
  left: Tree<T>;
  right: Tree<T>;
}

关于类型别名和接口的区别,笔者前面在TypeScript学习之接口一文中有讲解,感兴趣的小伙伴可以自行查看。

系列文章

TypeScript入门之环境搭建

TypeScript入门之数据类型

TypeScript入门之函数

TypeScript入门之接口

TypeScript入门之类

TypeScript入门之类型推断、类型断言、双重断言、非空断言、确定赋值断言、类型守卫、类型别名

TypeScript入门之泛型

TypeScript入门之装饰器

TypeScript入门之模块与命名空间

TypeScript入门之申明文件

TypeScript入门之常用内置工具类型

TypeScript入门之配置文件

后记

感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!

相关文章
|
2月前
|
设计模式 JavaScript 安全
TypeScript性能优化及代码质量提升的重要性、方法与策略,包括合理使用类型注解、减少类型断言、优化模块导入导出、遵循编码规范、加强代码注释等
本文深入探讨了TypeScript性能优化及代码质量提升的重要性、方法与策略,包括合理使用类型注解、减少类型断言、优化模块导入导出、遵循编码规范、加强代码注释等,旨在帮助开发者在保证代码质量的同时,实现高效的性能优化,提升用户体验和项目稳定性。
47 6
|
2月前
|
开发框架 JavaScript 前端开发
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
43 2
|
2月前
|
JavaScript 安全 前端开发
TypeScript类型声明:基础与进阶
通过本文的介绍,我们详细探讨了TypeScript的基础与进阶类型声明。从基本数据类型到复杂的泛型和高级类型,TypeScript提供了丰富的工具来确保代码的类型安全和可维护性。掌握这些类型声明能够帮助开发者编写更加健壮和高效的代码,提高开发效率和代码质量。希望本文能为您在使用TypeScript时提供实用的参考和指导。
40 2
|
2月前
|
JavaScript 开发者
在 Babel 插件中使用 TypeScript 类型
【10月更文挑战第23天】可以在 Babel 插件中更有效地使用 TypeScript 类型,提高插件的开发效率和质量,减少潜在的类型错误。同时,也有助于提升代码的可理解性和可维护性,使插件的功能更易于扩展和升级。
|
3月前
|
JavaScript 前端开发
TypeScript【类型别名、泛型】超简洁教程!再也不用看臭又长的TypeScript文档了!
【10月更文挑战第11天】TypeScript【类型别名、泛型】超简洁教程!再也不用看臭又长的TypeScript文档了!
|
3月前
|
JavaScript 前端开发 安全
TypeScript【基础类型】超简洁教程!再也不用看臭又长的TypeScript文档了!
【10月更文挑战第9天】TypeScript【基础类型】超简洁教程!再也不用看臭又长的TypeScript文档了!
|
3月前
|
JavaScript 前端开发 开发者
深入理解TypeScript:类型系统与最佳实践
【10月更文挑战第8天】深入理解TypeScript:类型系统与最佳实践
|
3月前
|
移动开发 JavaScript 前端开发
TypeScript:数组类型&函数使用&内置对象
本文介绍了 TypeScript 中的数组类型、对象数组、二维数组、函数、函数重载、内置对象等概念,并通过代码示例详细展示了它们的使用方法。还提供了一个使用 HTML5 Canvas 实现的下雨效果的小案例。
|
2月前
|
JavaScript 前端开发 安全
TypeScript进阶:类型系统与高级类型的应用
【10月更文挑战第25天】TypeScript作为JavaScript的超集,其类型系统是其核心特性之一。本文通过代码示例介绍了TypeScript的基本数据类型、联合类型、交叉类型、泛型和条件类型等高级类型的应用。这些特性不仅提高了代码的可读性和可维护性,还帮助开发者构建更健壮的应用程序。
34 0
|
3月前
|
JavaScript 前端开发 开发者
深入理解TypeScript:类型系统与实用技巧
【10月更文挑战第8天】深入理解TypeScript:类型系统与实用技巧