TypeScript 概述和基本应用 学习笔记

文章内容输出来源:拉勾大前端高薪训练营

TypeScript 概述

TypeScript 是基于 JavaScript 基础之上的编程语言,是 JavaScript 的超集(superset) 或者叫 扩展集 。任何一种 JavaScript 运行环境都支持
TypeScript 在JavaScript之上多了一些扩展特性:类型系统、ES6+,最终编译成原始的JavaScript。
TypeScript 解决 JavaScript 自由的类型系统的问题,大大提高代码的可靠程度。

相比较于 Flow ,TypeScript 功能更为强大,生态也更健全、更完善。
目前 Angular/Vue.js 3.0 已经使用 TypeScript。
TypeScript 是前端领域中的第二语言

缺点:(相对于JavaScript)

  • 语言本身多了很多概念,但是 TypeScript 属于[渐进式]:即便什么特性都不知道,可以立马按照JavaScript 标准语法来编写代码,可以了解一些特性,使用一些特性
  • 项目初期,TypeScript 会增加一些成本

基本使用

tsc 命令 作用:编译TypeScript文件,编译过程中先去检查代码中的类性使用异常,移除掉一些类型注解之类的扩展语法,自动转换ES的新特性。

//初始化 package.json 用来管理项目的依赖项
yarn init -yes
//作为项目的开发依赖安装,它提供 tsc 命令
yarn add typescript --dev
//编译文件
yarn tsc index.ts

tsc 命令 不仅可以编译指定的某个ts文件,还可以编译整个工程。
一般编译项目之前,先创建一个 typescript 的配置文件

//生成 tsconfig.json 文件
yarn tsc --init 

使用,直接运行命令:yarn tsc

TypeScript 基本应用

1、原始数据类型

标准库就是内置对象所对应的声明
Symbol、Promise 都是 ES2015标准库内置的
console 是DOM 标准库内置的
严格模式下 string、number、boolean 不能为空null
非严格模式下 可以为空

const a: string = 'footbar'
const b: number = 100 //NaN Infinity
const c: boolean = true // false
// const d: string = null
const e: void = undefined 
const f: null = null
const g: undefined = undefined
// const h: symbol = Symbol()

2、中文错误信息

yarn tsc --locale zh-CN

VScode 错误提示可以改配置: typescript locale : zh-CN
不推荐这么做,因为不利于搜索引擎去搜索错误信息

3、作用域

确保跟其它示例没有成员冲突 的办法:

//第一种
(function(){
    const a = 123
})()
//第二种 每个文件添加
export {}

4、Object 类型

  • object 不单指对象,指除了原始类型以外的其他类型
  • 对象的类型限制可以使用类似字面量语法的方式,更专业的方式是接口
const foo: object = function () {}
const obj: { foo: number, bar: string } = { foo: 123, bar: 'string' }

5、数组类型

const arr1: Array = [1, 2, 3]
const arr2: number[] = [1, 2, 3]

function sum(...args: number[]){
  return args.reduce((prev, current) => prev + current, 0)
}
sum(1, 2, 3)

6、元组类型:

明确元素的个数和每个元素的类型
react 中useState 这样的 Hooks 函数返回的就是元组类型
ES2017中提供 Object.entries()方法获取对象中所有的键值数组,得到的每一个键值就是元组,因为它是固定长度的

const tuple: [number, string] = [18, 'zs'];
// const age = tuple[0]
// const name = tuple[1]
const [age, name] = tuple
Object.entries({
  foo: 123,
  bar: 456
})

7、枚举类型:

  • 默认枚举类型的值从0开始累加,也可以设置第一个值,后面的值在这个值基础之上累加,枚举类型的值也可以为字符串,必须每个成员设置值。
  • 枚举类型 会入侵我们到我们运行时的代码(影响我们编译后的结果),编译成双向键值对的对象
  • 如果确定代码中不会使用索引器的方式使用枚举(PostStatus[0]),可以使用常量枚举,enum 前面添加 const,这样在编译过程中枚举会移除掉,用到枚举值的地方替换成对应的枚举值。
// const PostStatus = {
//   Draft: 0,
//   Unpublished: 1,
//   Published: 2
// }
// enum PostStatus {
//   Draft = 0,
//   Unpublished = 1,
//   Published = 2
// }
enum PostStatus {
  Draft,
  Unpublished,
  Published
}
// enum PostStatus {
//   Draft = 6,
//   Unpublished,
//   Published
// }
// enum PostStatus {
//   Draft = 'aaa',
//   Unpublished = 'bbb',
//   Published = 'ccc'
// }
const post = {
  title: 'hello typescript',
  content: 'typescript is a typed superset of javascript',
  status: PostStatus.Draft, //1, 0
}

编译之后

var PostStatus;
(function (PostStatus) {
    PostStatus[PostStatus["Draft"] = 0] = "Draft";
    PostStatus[PostStatus["Unpublished"] = 1] = "Unpublished";
    PostStatus[PostStatus["Published"] = 2] = "Published";
})(PostStatus || (PostStatus = {}));
var post = {
    title: 'hello typescript',
    content: 'typescript is a typed superset of javascript',
    status: PostStatus.Draft,
};

常量枚举

const enum PostStatus {
  Draft,
  Unpublished,
  Published
}
const post = {
  title: 'hello typescript',
  content: 'typescript is a typed superset of javascript',
  status: PostStatus.Draft, //1, 0
}
// 编译后
var post = {
    title: 'hello typescript',
    content: 'typescript is a typed superset of javascript',
    status: 0 /* Draft */,
};

8、函数类型:

函数可以采用 函数申明和函数表达式两种方式生成。
函数申明类型约束:

  • 函数每个参数后面添加类型注解,返回值的类型添加在 括号 后面。
  • 形参和实参 类型和个数必须要相同
  • 可选参数,在参数名称后面添加 '?',也可以使用es6的参数默认值的方式,这两种都必须放在参数列表的最后
  • 任意个数的参数使用 rest关键词(...rest)
function func1( a: number, b?:number, c: number = 10, ...rest: number[] ): string {
  return 'func1'
}
func1(100, 200);
func1(100);

函数表达式类型限制:

  • 可以使用相同的方式限制函数的参数和返回值的类型
  • typescript能根据函数表达式推断出这个变量的类型
  • 如果回调函数的方式,必须约束回调函数形参的类型,可以使用类似箭头函数的方式去表示参数可以接收什么的函数
const func2 = function(a: number, b: number): string {
  return 'func2';
}
const func3: (a: number, b:number) => string = function(a: number, b: number): string {
  return 'func2';
}

9、任意类型:

存在安全问题,不对any做类型检查,任何类型语法上都不会报错。
any 是不安全的,轻易不要使用。

function stringify( value: any ){
  return JSON.stringify(value)
}
stringify('string')
stringify(123)
stringify(true)

10、隐式类型推断:

如果没有明确表明类型,typescript会根据变量的使用情况推断变量的类型。
如果无法推断就标注为any
建议给每个变量添加明确的类型,因为这样会便于后期更直观的理解我们的代码

let age = 18;
age = 'string'; //报错
let foo
foo = 100
foo = 'string'

11、类型断言:

两种方式:as 、<>
断言是编译过程中的概念,转换是运行阶段的概念
类型断言不是类型转换,代码编译过后断言就不存在了

const nums = [110, 120, 119, 112];
const res = nums.find(i => i > 0);
// const square = res * res;
// 第一种 断言方式
const num1 = res as number; 
// 第二种 断言方式
const num2 = res; // 会jsx 标签产生冲突

12、接口(interfaces)

可以理解成 一种规范或者契约,用来约束对象的结构,使用一个接口,就必须遵守接口全部的约束

  • interface 开头,多个字段用 ,/; 也可以不加
  • 可选成员、只读成员、动态成员
interface Post {
  title: string,
  content: string;
  subtitle?: string //可选成员
  readonly summary: string //只读成员
}
function printPost(post: Post){
  console.log(post.title);
  console.log(post.content);
}
const hello: Post = {
  title: 'Hello TypeScript',
  content: 'A javascript superset',
  summary: 'A javascript'
}
printPost(hello);
// hello.summary = 'jajja'; //报错

//动态成员
interface Cache{
  [key: string]: string
}
const cache: Cache = {}
cache.foo = 'values';
cache.bar = 'hahha';

13、类 Classes

作用:用来描述一类具体事物的抽象特征
代码中:用来描述一类具体对象的抽象成员
ES6 中开始有专门的class,TypeScript 增强了 class 的相关语法

  • 需要先明确申明类有的一些属性
  • 属性必须设置默认值(可以在类中定义通过‘=’添加,也可以在构造函数中初始化)
class Person{
  name: string
  age: number
  constructor(name: string, age: number){
    this.name = 'init name';
    this.age = 18
  }
  sayHi( msg: string): void{
    console.log(`I am ${this.name}, ${msg}`)
  }
}

13.1、类的访问修饰符

控制类中成员的可访问级别

  • 默认是 public,
  • private私有属性:不能通过外部访问,只能类的内部使用
  • protected受保护的:不能通过外部访问,只允许在子类中访问
  • readonly只读属性
class Person{
  public name: string
  private age: number
  protected readonly gender: boolean
  constructor(name: string, age: number){
    this.name = 'init name';
    this.age = 18
    this.gender = true
  }
  sayHi( msg: string): void{
    console.log(`I am ${this.name}, ${msg}`)
    console.log(this.age)
  }
}
const tom = new Person('tom', 18);
console.log(tom.name)
// console.log(tom.age)// 报错
// console.log(tom.gender)// 报错
class Student extends Person{
  private constructor(name: string, age: number){
    super(name, age)
    console.log(this.gender)
  }
  static create(name: string, age: number) {
    return new Student(name, age);
  }
}
// const jack = new Student('jack', 18); //报错
const jack = Student.create('jack', 18);

13.2、类 与 接口

接口:抽取公共的特征
实现接口必须要有对应的所有的成员

interface Eat{
  eat(food: string): void
}
interface Run{
  run(distance: number): void
}
class Person implements Eat, Run{
  eat(food: string): void{
    console.log(`优雅的进餐:${food}`)
  }
  run(distance: number){
    console.log(`直立行走:${distance}`)
  }
}
class Animal implements Eat, Run{
  eat(food: string): void{
    console.log(`呼噜呼噜的吃:${food}`)
  }
  run(distance: number){
    console.log(`爬行:${distance}`)
  }
}

13.3、抽象类

class 前面加 abstract, 只能被继承,不能使用new创建的对应的实例对象,必须使用子类继承这个类型

  • 抽象方法需要使用 abstract 修饰,不需要方法体
  • 父类中有抽象方法时,子类必须实现它
    可以使用vscode 的代码修正功能,自动生成对应的方法实现
abstract class Animal{
  eat(food: string): void{
    console.log(`呼噜呼噜的吃:${food}`)
  }
  abstract run(distance: number): void
}
class Dog extends Animal{
  run(distance: number): void {
    console.log(`四脚爬行:${distance}`)
  }
}
const d = new Dog();
d.eat('骨头');
d.run(100);

13.4、泛型(Generics)

定义接口、函数或累的时候没有指定具体的类型,使用的时候再去指定具体的类型
目的:极大程度的复用代码

//创建指定长度的数组
function createNumberArray(length: number, value: number): number[]{
  const arr = Array(length).fill(value);
  return arr;
}
const res0 = createNumberArray(3, 100);
//
function createArray(length: number, value: T): T[]{
  const arr = Array(length).fill(value);
  return arr;
}
const res1 = createArray(3, 100); //[100, 100, 100]
const res2 = createArray(3, 'foo'); // ['foo', 'foo', 'foo']

13.5、类型申明(Type Declaration)

定义的时候没有明确的申明,使用时 申明(declare)
为了兼容普通的js模块
在TypeScript中引入第三方模块,如果模块中不包含对应的类型申明文件,我们就要安装对应的类型申明模块,"@types/模块名", 如果没有 只能自己用 declare 语句申明所对应的模块类型

import { camelCase }  from 'lodash'
declare function camelCase(input: string): string
const res = camelCase('hello typed');

你可能感兴趣的:(TypeScript 概述和基本应用 学习笔记)