极速上手TypeScript应用

154 min read

极速上手TypeScript应用

简介

  1. TypeScript是JavaScript的超集。
  2. 它对JS进行了扩展,向JS中引入了类型的概念,并添加了许多新的特性。
  3. TS代码需要通过编译器编译为JS,然后再交由JS解析器执行。
  4. TS完全兼容JS,换言之,任何的JS代码都可以直接当成JS使用。
  5. 相较于JS而言,TS拥有了静态类型,更加严格的语法,更强大的功能;TS可以在代码执行前就完成代码的检查,减小了运行时异常的出现的几率;TS代码可以编译为任意版本的JS代码,可有效解决不同JS运行环境的兼容问题;同样的功能,TS的代码量要大于JS,但由于TS的代码结构更加清晰,变量类型更加明确,在后期代码的维护中TS却远远胜于JS。

安装

  1. 下载Node.js

    • 64位:https://nodejs.org/dist/v14.15.1/node-v14.15.1-x64.msi
    • 32位:https://nodejs.org/dist/v14.15.1/node-v14.15.1-x86.msi
  2. 安装Node.js

  3. 使用npm全局安装typescript

    • 进入命令行
    • 输入:npm i -g typescript
  4. 创建一个ts文件

  5. 使用tsc对ts文件进行编译

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

基本类型

类型 例子 描述
number 1, -33, 2.5 任意数字
string 'hi', "hi", hi 任意字符串
boolean true、false 布尔值true或false
字面量 其本身 限制变量的值就是该字面量的值
any * 任意类型
unknown * 类型安全的any
void 空值(undefined) 没有值(或undefined)
never 没有值 不能是任何值
object {name:'孙悟空'} 任意的JS对象
array [1,2,3] 任意JS数组
tuple [4,5] 元素,TS新增类型,固定长度数组
enum enum{A, B} 枚举,TS中新增类型

TS的类型声明

作用

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

给变量设置了类型,使得变量只能存储某种类型的值

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

 语法

let 变量: 类型;

let 变量: 类型 = ;

function fn(参数: 类型, 参数: 类型): 类型{
    ...
}

字面量赋值

使用字面量进行类型声明,限制只能是声明的字面量,赋值其它值编译报错

let a: 10;

a = 10;

可以使用 | 来连接多个类型(联合类型),限制只能是其中一个字面量,赋值其它值编译报错

let b: "male" | "female";
b = "male";
b = "female";

void

用来表示空,以函数为例,就表示没有返回值的函数

function fn(): void{
}

unknown

表示未知类型的值,类型安全的any,unknown类型不能直接赋值给其它类型

let e: unknown;
e = "some test";

let s:string;

s = e; //报错
s = e as string; // 编译器不处理,手动声明后不报错,编译通过
s = <string> e; // 另一个语法形式

never

表示永远不会返回结果

function fn2(): never{
    throw new Error('报错了!');
}

object

语法:{属性名:属性值,属性名:属性值}

[propName: string]: any 表示任意类型的属性

let c: {name: string, [propName: string]: any};
c = {name: '猪八戒', age: 18, gender: '男'};

数组

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

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

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

元组

元组就是固定长度的数组

let h: [string, number];
h = ['hello', 123];

枚举

enum Gender{
    Male,
    Female
}

let i: {name: string, gender: Gender};
i = {
    name: '孙悟空',
    gender: Gender.Male // 'male'
}

类型断言

可以用来告诉解析器变量的实际类型

s = e as string;
s = <string>e;

生成 tsconfig.json

tsconfig.json是ts编译器的配置文件,ts编译器可以根据它的信息来对代码进行编译

$ tsc -v

如果版本大于1.6,则需要更新:

$ npm install -g typescript

请记住,需要安装node.js才能使用npm。

正确的命令--init不是init

$ tsc --init

默认生成的内容

{ 
  "include": ["*"], //定义希望被编译文件所在的目录
  "exclude": ["./src/hello/**/*"],// 默认值:["node_modules", "bower_components", "jspm_packages"]
  "compilerOptions": {
   
    /* Visit https://aka.ms/tsconfig.json to read more about this file */

    /* Basic Options */
    // "incremental": true,                   /* Enable incremental compilation */
    "target": "es5",                          /* 设置ts代码编译的目标版本 Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "commonjs",                     /* 设置编译后代码使用的模块化系统 Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
    // "lib": [],                             /* Specify library files to be included in the compilation. */
    // "allowJs": true,                       /* 是否对js文件编译 Allow javascript files to be compiled. */
    // "checkJs": true,                       /* 是否对js文件进行检查 Report errors in .js files. */
    // "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    // "declaration": true,                   /* Generates corresponding '.d.ts' file. */
    // "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
    // "sourceMap": true,                     /* Generates corresponding '.map' file. */
    // "outFile": "./",                       /* 将所有的文件编译为一个js文件 Concatenate and emit output to single file. */
    // "outDir": "./",                        /* 编译后文件的所在目录 默认情况下,编译后的js文件会和ts文件位于相同的目录,设置outDir后可以改变编译后文件的位置 Redirect output structure to the directory. */
    // "rootDir": "./",                       /* 指定代码的根目录,默认情况下编译后文件的目录结构会以最长的公共目录为根目录,通过rootDir可以手动指定根目录Specify the root directory of input files. Use to control the output directory structure with --outDir. */
    // "composite": true,                     /* Enable project compilation */
    // "tsBuildInfoFile": "./",               /* Specify file to store incremental compilation information */
    // "removeComments": true,                /* 是否删除注释 Do not emit comments to output. */
    // "noEmit": true,                        /* 不对代码进行编译 Do not emit outputs. */
    // "importHelpers": true,                 /* Import emit helpers from 'tslib'. */
    // "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
    // "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

    /* Strict Type-Checking Options */
    "strict": true,                           /* 启用所有的严格检查,默认值为true,设置后相当于开启了所有的严格检查 Enable all strict type-checking options. */
    // "noImplicitAny": true,                 /* 禁止隐式的any类型 Raise error on expressions and declarations with an implied 'any' type. */
    // "strictNullChecks": true,              /* 严格的空值检查 Enable strict null checks. */
    // "strictFunctionTypes": true,           /* 严格检查函数的类型 Enable strict checking of function types. */
    // "strictBindCallApply": true,           /* 严格检查bind、call和apply的参数列表 Enable strict 'bind', 'call', and 'apply' methods on functions. */
    // "strictPropertyInitialization": true,  /* 严格检查属性是否初始化 Enable strict checking of property initialization in classes. */
    // "noImplicitThis": true,                /* 禁止类型不明确的this Raise error on 'this' expressions with an implied 'any' type. */
    // "alwaysStrict": true,                  /* 总是以严格模式对代码进行编译 Parse in strict mode and emit "use strict" for each source file. */

    /* Additional Checks */
    // "noUnusedLocals": true,                /* 检查未使用的局部变量 Report errors on unused locals. */
    // "noUnusedParameters": true,            /* 检查未使用的参数 Report errors on unused parameters. */
    // "noImplicitReturns": true,             /* 检查函数没有隐式的返回值 Report error when not all code paths in function return a value. */
    // "noFallthroughCasesInSwitch": true,    /* 检查switch语句包含正确的break Report errors for fallthrough cases in switch statement. */
    // "noUncheckedIndexedAccess": true,      /* Include 'undefined' in index signature results */

    /* Module Resolution Options */
    // "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    // "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
    // "typeRoots": [],                       /* List of folders to include type definitions from. */
    // "types": [],                           /* Type declaration files to be included in compilation. */
    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
    // "allowUmdGlobalAccess": true,          /* Allow accessing UMD globals from modules. */

    /* Source Map Options */
    // "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */
    // "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
    // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */

    /* Experimental Options */
    // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */

    /* Advanced Options */
    "skipLibCheck": true,                     /* Skip type checking of declaration files. */
    "forceConsistentCasingInFileNames": true  /* Disallow inconsistently-cased references to the same file. */
  }
}

常用配置

{
  "include": [
    "./src/**/*"
  ],

  "compilerOptions": {


    "target": "es2015",

    "module": "es2015",

    // outDir 用来指定编译后文件所在的目录
    "outDir": "./dist",

    // 将代码合并为一个文件
    // 设置outFile后,所有的全局作用域中的代码会合并到同一个文件中
    //"outFile": "./dist/app.js"

    // 是否对js文件进行编译,默认是false
//    "allowJs": true,
    // 是否检查js代码是否符合语法规范,默认是false
//    "checkJs": true,
    // 是否移除注释
    "removeComments": true,
    // 不生成编译后的文件
    "noEmit": false,

    // 当有错误时不生成编译后的文件
    "noEmitOnError": true,

    // 所有严格检查的总开关
    "strict": true,

    // 用来设置编译后的文件是否使用严格模式,默认false
    "alwaysStrict": true,

    // 不允许隐式的any类型
    "noImplicitAny": true,

    // 不允许不明确类型的this
    "noImplicitThis": true,

    // 严格的检查空值
    "strictNullChecks": true


  }
}

面向对象

封装

  • 对象实质上就是属性和方法的容器,它的主要作用就是存储属性和方法,这就是所谓的封装
  • 默认情况下,对象的属性是可以任意的修改的,为了确保数据的安全性,在TS中可以对属性的权限进行设置
  • 如果在声明属性时添加一个readonly,则属性便成了只读属性无法修改

权限

  • public(默认值),可以在类、子类和对象中修改
  • protected ,可以在类、子类中修改
  • private ,可以在类中修改

构造函数

class Animal{
    name: string;
    age: number;

    constructor(name: string, age: number){
        this.name = name;
        this.age = age;
    }
}

GETTER/SETTER

  • 直接将其设置为private将导致无法再通过对象修改其中的属性
  • 我们可以在类中定义一组读取、设置属性的方法,这种对属性读取或设置的属性被称为属性的存取器
  • 读取属性的方法叫做setter方法,设置属性的方法叫做getter方法

静态属性

  • 静态属性(方法),也称为类属性。使用静态属性无需创建实例,通过类即可直接使用
  • 静态属性(方法)使用static开头

继承

  • 继承时面向对象中的又一个特性
  • 通过继承可以将其他类中的属性和方法引入到当前类中

抽象类

  • 抽象类是专门用来被其他类所继承的类,它只能被其他类所继承不能用来创建实例
  • 使用abstract开头的方法叫做抽象方法,抽象方法没有方法体只能定义在抽象类中,继承抽象类时抽象方法必须要实现

this/super

  • 在类中,使用this表示当前对象
  • 在类中,使用super表示父类对象

接口

接口的作用类似于抽象类,不同点在于接口中的所有方法和属性都是没有实值的,换句话说接口中的所有方法都是抽象方法。接口主要负责定义一个类的结构,接口可以去限制一个对象的接口,对象只有包含接口中定义的所有属性和方法时才能匹配接口。同时,可以让一个类去实现接口,实现接口时类中要保护接口中的所有属性。

interface Person{
    name: string;
    sayHello():void;
}

function fn(per: Person){
    per.sayHello();
}

fn({name:'孙悟空', sayHello() {console.log(`Hello, 我是 ${this.name}`)}});

实现接口

interface Person{
    name: string;
    sayHello():void;
}

class Student implements Person{
    constructor(public name: string) {
    }

    sayHello() {
        console.log('大家好,我是'+this.name);
    }
}

泛型

定义一个函数或类时,有些情况下无法确定其中要使用的具体类型(返回值、参数、属性的类型不能确定),此时泛型便能够发挥作用。

函数泛型

function test<T>(arg: T): T{
	return arg;
}

类泛型

class MyClass<T>{
    prop: T;

    constructor(prop: T){
        this.prop = prop;
    }
}

多个泛型

多个泛型使用逗号隔开

function test<T, K>(a: T, b: K): K{
    return b;
}

test<number, string>(10, "hello");

泛型约束

使用T extends MyInter表示泛型T必须是MyInter的子类,不一定非要使用接口类和抽象类同样适用。

interface MyInter{
    length: number;
}

function test<T extends MyInter>(arg: T): number{
    return arg.length;
}