基础-TypeScript初探

141 阅读12分钟

一、基础知识

1、定义

TypeScript 由微软开发的一款开源的编程语言。

TypeScript 是 JavaScript 的超集,支持 ECMAScript 6 标准。TypeScript 扩展了Javascript语法。

知识扩展:

1)以javaScript 为基础构建的语言;

2)一个javaScript的超集;

3)可以在任何支持JavaScript的平台中执行;

4)TypeScript扩展了JavaScript,并添加了类型;

5)TS不能被Js解析器直接执行;

简而言之,TypeScript是JavaScript的超集,具有可选的类型并可以编译为纯JavaScript。从技术上讲TypeScript就是具有静态类型的 JavaScript 。

2、特性

TypeScript 热度不断攀升,主要两类特性:

1)TypeScript 支持 JavaScript。开发者只需将文件扩展名从 .js 改为 .ts,就实现了从 JavaScript 到 TypeScript 最简单转换。

2)TypeScript 提供了强大的类型系统。类型系统是 TypeScript 和 JavaScript 最大的差别。

TypeScript 转换为 JavaScript 过程如下图:

3、使用理由

1)Ts提供的类型系统可以帮助我们在写代码的时候提供更丰富的语法提示;

2)在创建前的编译阶段经过类型系统的检查,就可以避免很多线上的错误。

4、增加功能

1)类型;

2)支持ES的新特性;

3)强大的开发工具;

4)添加ES不具备的新特性;

5)丰富的配置选项;

扩展:

  1. debug很久,最后发现是变量名写错时的绝望吗?

  2. 生产线上代码出现Uncaught TypeError (未知类型错误)时的恐惧吗?

  3. 写代码找一万个文件还找不到方法定义时委屈吗?

  4. ts是js的超集,意味着js本身的语法在ts里面也能跑的通。ts需要编译成js才能运行。

**说明:**TypeScript是和vscode都是微软的。

二、环境搭建

1、操作流程

1)创建一个ts文件

2)使用tsc 对ts文件进行编译

  • 进入命令行
  • 进入 ts 文件所在目录
  • 执行命令: tsc xxx.ts

注:node 版本下载:1) LTS(稳定版) 2)Current(当前版) (建议使用稳定版本)

node 版本:nodejs.org/en/download…

2、详细流程

安装 typescript:

npm install -g typescript

安装完成后我们可以使用 tsc 命令来执行 TypeScript 的相关代码,以下是查看版本号:

$ tsc -v
Version 4.7.3

然后我们新建一个 app.ts 的文件,代码如下:

var message:string = "Hello World" 
console.log(message)

以下命令将 TypeScript 转换为 JavaScript 代码:

tsc app.ts

生成 tsconfig.json 配置文件

tsc --init

执行命令后我们就可以看到生成了一个 tsconfig.json 文件,里面有一些配置信息

三、基础语法

TypeScript 程序由以下几个部分组成:

  • 模块

  • 函数

  • 变量

  • 语句和表达式

  • 注释

TypeScript 保留关键字

1)空白和换行

TypeScript 会忽略程序中出现的空格、制表符和换行符。

空格、制表符通常用来缩进代码,使代码易于阅读和理解。

2)TypeScript 区分大小写

TypeScript 区分大写和小写字符。

3)TypeScript 支持两种类型的注释

单行注释 ( // ) − 在 // 后面的文字都是注释内容。

多行注释 (/* */) − 这种注释可以跨越多行。

四、基础类型

类型声明

*类型声明是TS非常重要的一个特点;

通过类型声明可以指定TS中变量(参数、形参)的类型

指定类型后,当为变量赋值时,TS编辑器会自动检查值是否符合类型声明,符合则赋值,否则报错

简页言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值

语法:

let 变量:类型;
let 变量:类型 = 值;
function fn(参数:类型,参数:类型): 类型{
  ......
}

*类型说明(要)

详情说明:

1、number/string/boolean

  1. 变量进行类型声明,直接在变量后边加就可以;

    // 声明一个变量a,同时指定它的类型为number let a: number;

    // a 的类型设置为了number,在以后的使用过程中a的值只能是数字 a = 10; a = 33; a = 'hello'; // 此行代码会报错,因为变量a的类型是number,不能赋值字符串

  2. 如果变量的声明和赋值是同时进行的,TS可以自动对变量进行类型检测;

    // 如果变量的声明和赋值是同时进行的,TS可以自动对变量进行类型检测 let c = false; c = true;

  3. 函数中运用:1、参数类型,2、返回值类型(函数要考虑参数的类型和个数)

    // js中的函数是不考虑参数的类型和个数的 function sum(a, b){ return a + b; } console.log(sum(123, 456)); // 579 console.log(sum(a:123, b:'456')); // '123456'

    function sum(a: number, b: number){ return a + b; } sum(a: 123, b: 345)

2、字面量/any/unknown/类型断言

  1. 字面量

    // 可以直接使用字面量进行类型声明 let a: 10; a = 10;

    // 可以使用 | 来连接多个类型(联合类型) let b: "male" | "female"; b = "male"; b = "female";

    let c: boolean | string; c = true; c = "hello";

  2. any 表示的是任意类型

    // any 表示的是任意类型,一个变量设置类型为any后相当于对该变量关闭了TS的类型检测 // 使用 TS时,不建议使用any类型 let d: any; d = 10; d = 'hello'; d = true;

    // 声明变量如果不指定类型,则TS解析器会自动判断变量的类型为any(隐式的any) let d: d = 10; d = 'hello'; d = true;

  3. unknown 表示未知类型的值

    // unknown 实际上就是一个类型安全的any let e: unknown; e = 10; e = 'hello'; e = true;

    // unknown类型的变量,不能直接赋值给其他变量 if(typeof e === 'string') { s = e; }

  4. 类型断言

    // 类型断言,可以用来告诉解析器变量的实际类型 // 语法:1)变量 as 类型 2)<类型> 变量 s = e as string; s = e;

  5. void 用来表示空

    // void 用来表示空,为函数为例,就表示没有返回值的函数 function fn(): void{ }

  6. never 表示永远不会返回结果

    // never 表示永远不会返回结果 function fn2(): never{ throw new Error('报错了'); }

3、对象/数组/元组/枚举

1) 对象属性

// object 表示一个js对象
let a: object;
a = {};
a = function () {
};


// {} 用来指定对象中可以包含哪些属性
// 语法: {属性名:属性值,属性名:属性值}
let b:{name: string, age: number};
b = {name: '孙悟空', age: 18}

// 在属性名后加上?,表示属性是可选的
let b:{name: string, age?: number};
b = {name: '孙悟空', age: 18}
       
// [propName: string]: any 表示任意类型的属性
let b:{name: string, [propName: string]: any};
b = {name: '孙悟空', age: 18, gender: '男'}

// 设置函数结构的类型声明 
// 语法:(形参:类型,形参:类型...)=> 返回值
let d: (a: number, b: number) => number;

2) 数组的类型声明 1)类型[] 2)Array<类型>

// 数组的类型声明:1)类型[] 2)Array<类型>

// string[] 表示字符串数组
let e: string[];
e = ['a', 'b', 'c'];

// number[] 表示数值数组
let f: number[];

let g: Array<number>;
g = [1, 2, 3]

3) 元组,固定长度的数组

元组( Tuple )表示一个已知数量和类型的数组,可以理解为他是一种特殊的数组

// 元组,就是固定长度的数组
// 语法:[类型,类型,类型]
let h: [string, number];
h = ['hello', 123];

4) 枚举 enum

let i: {name: string, gender: 0 | 1};
i = {
  name: '张三',
  gender: 1
}

console.log(i.gender === 1);

// enum 枚举
enum Gender{
  Male = 0;
  Female = 1;
}
let i: {name: string, gender: Gender};
i = {
  name: '张三',
  gender: Gender.Male // 'male'
}
console.log(i.gender === Gender.Male);

5) & 表示同时

// & 表示同时
let j: { name: string } & { age: number};
j = {name: '张三', age: 18};

6) 类型的别名

type myType = 1|2|3|4|5;
let k: myType;
let l: myType;
let m: myType;

五、interface 接口

接口来定义对象的类型。接口是对象的状态(属性)和行为(方法)的抽象(描述)

简单理解就是:为我们的代码提供一种约定。

详情:接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法,同时接口也可以当成类型声明去使用。

(function (){
  // 描述一个对象的类型
  type myType = {
    name: string,
    age: number
  }
  
  const obj: myType = {
    name: 'sss',
    age: 111
  }
})

(function (){
  // 接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法
  // 同时接口也可以当成类型声明去使用
  interface myInterface{
    name: string,
    age: number
  }
  
  const obj: myInterface = {
    name: 'sss',
    age: 111
  }
})

// 接口可以在定义类的时候去限制类的结构,
// 接口中的所有的属性都不能有实际的值
// 接口只定义对象的结构,而不考虑实际值
interface myinter{
  name: string;
  sayHello():void;
}

// 定义类时,可以使类去实现一个接口,
// 实现接口就是使类满足接口的要求
class MyClass implements myInter {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  sayHello() {
    console.log('大家好')
  }
}

六、泛型

泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

在定义函数或是类时,如果遇到类型不明确就可以使用泛型。

// 在定义函数或是类时,如果遇到类型不明确就可以使用泛型
function fn<T>(a: T): T{
  return a;
}

// 可以直接调用具有泛型的函数
fn(a: 10); // 不指定泛型,TS可以自动对类型进行推断
fn<string>(a: 'hello'); //指定泛型

1、泛型可以同时指定多个

// 泛型可以同时指定多个
function fn2<T,K>(a: T, b: K):T {
  console.log(b);
  return a;
}
fn2<number, string>(a:123, b: 'hello');

2、泛型T必须是Inter实现类(子类)

interface Inter{
  length: number;
}

// T extends Inter 表示泛型T必须是Inter实现类(子类)
function fn3<T extends Inter>(a: T):number {
  return a.length;
}

class MyClass<T>{
  name: T;
  constructor(name: T) {
    this.name = name;
  }
}

const mc = new MyClass<string>(name: '张三');

七、编译选项

1、自动编译文件

编译文件时,使用-w指令后,TS编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。

示例

tsc xxx.ts -w

2、自动编译整个项目

如果直接使用tsc指令,则可以自动将当前项目下的所有ts文件编译为js文件。

但是能直接使用tsc命令的前提时,要先在项目根目录下创建一个ts的配置文件 tsconfig.json

tsconfig.json是一个json文件,添加配置文件后,只需要tsc命令即可完成对整个项目的编译;

配置选项 tsconfig.json 文件

{
  /*
    tsconfig.json是ts编译器的配置文件,ts编译器可以根据它的信息来对代码进行编辑
  */
  // 用来指定哪些ts文件需要被编译  
  // 路径:1)** 表示任意目录 2)* 表示任意文件
  "include": [
    "./src/**/*"
  ],
  // exclude 不需要被编译的文件目录 
  // 默认值:["node_modules", "bower_components", "jspm_packages"]
  "exclude": [
    "./src/hello/**/*"
  ],
  // compilerOptions 编译器的选项
  "compilerOptions": {
    "target": "es2015", // 用来指定ts被编译为的es版本
    "module": "commonjs", // 指定要使用的模块化的规范
    "outDir": "./dist", // 用来指定编译后文件所在的目录
    "outFile": "./dist/app.js" //  将代码合并为一个文件
    // 是否对js文件进行编译,默认是false
    "allowJs": true,
    // 是否检查js代码是否符合语法规范,默认是false
    "checkJs": true,
    // 是否移除注释
    "removeComments": true,
    // 所有严格检查的总开关
    "strict": true,
 
    // 用来设置编译后的文件是否使用严格模式,默认false
    "alwaysStrict": true,
    
    // 不允许隐式的any类型
    "noImplicitAny": true,
    
    // 不充许不明确类型的this
    "noImplicitThis": true,
    
    // 严格的检查空值
    "strictNullChecks": false
  }
 
}

compilerOptions 选项(重要)

{
  "compilerOptions": {

    /* 基本选项 */
    "target": "es5",                       // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
    "module": "commonjs",                  // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
    "lib": [],                             // 指定要包含在编译中的库文件
    "allowJs": true,                       // 允许编译 javascript 文件
    "checkJs": true,                       // 报告 javascript 文件中的错误
    "jsx": "preserve",                     // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
    "declaration": true,                   // 生成相应的 '.d.ts' 文件
    "sourceMap": true,                     // 生成相应的 '.map' 文件
    "outFile": "./",                       // 将输出文件合并为一个文件
    "outDir": "./",                        // 指定输出目录
    "rootDir": "./",                       // 用来控制输出目录结构 --outDir.
    "removeComments": true,                // 删除编译后的所有的注释
    "noEmit": true,                        // 不生成输出文件
    "importHelpers": true,                 // 从 tslib 导入辅助工具函数
    "isolatedModules": true,               // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).

    /* 严格的类型检查选项 */
    "strict": true,                        // 启用所有严格类型检查选项
    "noImplicitAny": true,                 // 在表达式和声明上有隐含的 any类型时报错
    "strictNullChecks": true,              // 启用严格的 null 检查
    "noImplicitThis": true,                // 当 this 表达式值为 any 类型的时候,生成一个错误
    "alwaysStrict": true,                  // 以严格模式检查每个模块,并在每个文件里加入 'use strict'

    /* 额外的检查 */
    "noUnusedLocals": true,                // 有未使用的变量时,抛出错误
    "noUnusedParameters": true,            // 有未使用的参数时,抛出错误
    "noImplicitReturns": true,             // 并不是所有函数里的代码都有返回值时,抛出错误
    "noFallthroughCasesInSwitch": true,    // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)

    /* 模块解析选项 */
    "moduleResolution": "node",            // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
    "baseUrl": "./",                       // 用于解析非相对模块名称的基目录
    "paths": {},                           // 模块名到基于 baseUrl 的路径映射的列表
    "rootDirs": [],                        // 根文件夹列表,其组合内容表示项目运行时的结构内容
    "typeRoots": [],                       // 包含类型声明的文件列表
    "types": [],                           // 需要包含的类型声明文件名列表
    "allowSyntheticDefaultImports": true,  // 允许从没有设置默认导出的模块中默认导入。

    /* Source Map Options */
    "sourceRoot": "./",                    // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
    "mapRoot": "./",                       // 指定调试器应该找到映射文件而不是生成文件的位置
    "inlineSourceMap": true,               // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
    "inlineSources": true,                 // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性

    /* 其他选项 */
    "experimentalDecorators": true,        // 启用装饰器
    "emitDecoratorMetadata": true          // 为装饰器提供元数据的支持
  }
}