typescript

#【第一篇:写在前面】

(1) ts是微软开发并开源的编程语言,是js的超集,在js的基础上又进行了拓展,如interface、泛型、枚举等等。ts最大的核心就是为js增加了类型检查。

(2) ts与我们学的其他语言不同,如sass、vue、webpack等,这些语言的代码只要出现语法问题,必然会在浏览器或其他地方报出错误;但是ts不同,如果代码不符合ts语法但符合js语法,是仍然能运行的,因为ts最终是转成js运行的。

(3) 所以ts只是相对的为js增加了类型检查,而不是像其他语言如java一样,是绝对的类型校验。因此,使用ts开发需要开发人员主动的解决ts语法错误;说实在的,这对开发人员的自觉性有较高的要求。

  • 举个例子
//Person类
class Person {
  private name: string;
  constructor(name:string) {
    this.name = name;
  }
}

let p = new Person('Tom');
console.log(p.name); //在ts中会提示:属性“name”为私有属性,只能在类“Person”中访问
//但是在js中,仍然能得到 Tom

(4) ts分为正常模式严格模式,默认是正常模式;两种情况的有些表现有所不同,建议使用严格模式,否则可能与你预想的情况有所不同,特别是处女座的。

//tsconfig.json
{
    "compilerOptions": {
        "strictNullChecks": true, //管null和undefined严格的
        "strict": true, //全部严格
    }
}


#【第二篇:工具篇】

#安装工具

typescript: 首先,浏览器或nodejs是不能直接运行.ts文件的,需要安装.ts转换工具typescript,typescript工具会将.ts文件转换成.js文件;

  • 全局安装:npm i typescript -g
  • 安装到项目:npm i typescript -D

ts-node: nodejs执行.ts文件时,是先使用typescript工具将.ts文件转换成.js文件,再使用node ./xx.js来执行;比较麻烦,我们可以使用ts-node工具直接运行.ts文件(其实是其内部做了一层处理,本质还是使用node运行.js文件)

  • 全局安装:npm i ts-node -g
  • 安装到项目:npm i ts-node -D

#工具的使用

  • 全局安装

    • typescript:直接运行tsc ./one.ts,就能将.ts文件转成.js文件了
    • ts-node:直接运行ts-node ./one.ts,直接在node输出内容了
  • 安装到项目中

    • 第一种:需要在命令前加npx,比如:npx tsc ./one.tsnpx ts-node ./one.ts
    • 第二种:需要在package.json中的scripts下添加命令,如下:
    //package.json
    {
      "scripts": {
         "tsc": "tsc ./one.ts",
         "ts-node": "ts-node ./one.ts"
      }
    }
    //执行npm run tsc ,等同于 tsc ./one.ts
    //执行npm run ts-node,等同于 ts-node ./one.ts
    

# typescript工具的 tsc 命令

typescript工具安装成功之后,会带有一个tsc命令,来执行.ts的转换,常见命令如下:

  • tsc ./one.ts:直接在当前目录生成转译的one.js文件,该命令只能转译单个文件,不能转译文件夹。
  • tsc --init:生成tsconfig.json配置文件
  • tsc:根据当前项目根目录的tsconfig.json文件进行转译
  • tsc --project tsconfig.production.json:根据指定的配置文件进行转译,--project可简写为-p
  • tsc --watch:在tsc命令下添加一个监听,--watch可简写为-w

# tsconfig.json配置文件

  • 基础输入输出
{
  "compilerOptions": {
    "outFile": "",
    "rootDir": "",
    "outDir": ""
  },
  "files": [
    "./one.ts",
    "./ts/n1.ts"
  ],
  "include": [],
  "exclude": []
}

/* 
compilerOptions:编译器配置,参数是对象,包含了很多编译器配置

files:参数是数组,指定需要编译的.ts文件;不要省略.ts后缀
      生成的.js文件与.ts文件同名且在同一文件夹下;
include:参数是数组,指定需要编译的文件或文件夹;可以使用正则模糊指定;
        会与files指定的文件取并集;
exclude:参数是数组,过滤不需要被编译的文件或文件夹;可以使用正则模糊过滤;
        会过滤到include指定的文件或文件夹;但不会过滤掉files指定的文件;


---------------------------------------------------------------------------

compilerOptions下属性:
 {
   "outFile": '',  //将多个相互依赖的文件生成一个文件,仅支持amd模块和system模块
   "rootDir": '',  //指定一个文件夹,里面是需要所有需要转换的.ts文件
                   //若是除了这个文件还有其他需要转换的ts文件,则会报错;此时可以使用exclude排除
   "outDir": '',   //指定一个文件夹,存放所有编译之后的.js文件              
 }
*/
"compilerOptions": {
  "incremental": true, // TS编译器在第一次编译之后会生成一个存储编译信息的文件,第二次编译会在第一次的基础上进行增量编译,可以提高编译的速度
  "tsBuildInfoFile": "./buildFile", // 增量编译文件的存储位置
  "diagnostics": true, // 打印诊断信息 
  "target": "ES5", // 目标语言的版本
  "module": "CommonJS", // 生成代码的模板标准
  "outFile": "./app.js", // 将多个相互依赖的文件生成一个文件,可以用在AMD模块中,即开启时应设置"module": "AMD",
  "lib": ["DOM", "ES2015", "ScriptHost", "ES2019.Array"], // TS需要引用的库,即声明文件,es5 默认引用dom、es5、scripthost,如需要使用es的高级版本特性,通常都需要配置,如es8的数组新特性需要引入"ES2019.Array",
  "allowJS": true, // 允许编译器编译JS,JSX文件
  "checkJs": true, // 允许在JS文件中报错,通常与allowJS一起使用
  "outDir": "./dist", // 指定输出目录
  "rootDir": "./", // 指定输出文件目录(用于输出),用于控制输出目录结构
  "declaration": true, // 生成声明文件,开启后会自动生成声明文件
  "declarationDir": "./file", // 指定生成声明文件存放目录
  "emitDeclarationOnly": true, // 只生成声明文件,而不会生成js文件
  "sourceMap": true, // 生成目标文件的sourceMap文件
  "inlineSourceMap": true, // 生成目标文件的inline SourceMap,inline SourceMap会包含在生成的js文件中
  "declarationMap": true, // 为声明文件生成sourceMap
  "typeRoots": [], // 声明文件目录,默认时node_modules/@types
  "types": [], // 加载的声明文件包
  "removeComments":true, // 删除注释 
  "noEmit": true, // 不输出文件,即编译后不会生成任何js文件
  "noEmitOnError": true, // 发送错误时不输出任何文件
  "noEmitHelpers": true, // 不生成helper函数,减小体积,需要额外安装,常配合importHelpers一起使用
  "importHelpers": true, // 通过tslib引入helper函数,文件必须是模块
  "downlevelIteration": true, // 降级遍历器实现,如果目标源是es3/5,那么遍历器会有降级的实现
  "strict": true, // 开启所有严格的类型检查
  "alwaysStrict": true, // 在代码中注入'use strict'
  "noImplicitAny": true, // 不允许隐式的any类型
  "strictNullChecks": true, // 不允许把null、undefined赋值给其他类型的变量
  "strictFunctionTypes": true, // 不允许函数参数双向协变
  "strictPropertyInitialization": true, // 类的实例属性必须初始化
  "strictBindCallApply": true, // 严格的bind/call/apply检查
  "noImplicitThis": true, // 不允许this有隐式的any类型
  "noUnusedLocals": true, // 检查只声明、未使用的局部变量(只提示不报错)
  "noUnusedParameters": true, // 检查未使用的函数参数(只提示不报错)
  "noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即如果没有break语句后面不会执行)
  "noImplicitReturns": true, //每个分支都会有返回值
  "esModuleInterop": true, // 允许export=导出,由import from 导入
  "allowUmdGlobalAccess": true, // 允许在模块中全局变量的方式访问umd模块
  "moduleResolution": "node", // 模块解析策略,ts默认用node的解析策略,即相对的方式导入
  "baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录
  "paths": { // 路径映射,相对于baseUrl
    // 如使用jq时不想使用默认版本,而需要手动指定版本,可进行如下配置
    "jquery": ["node_modules/jquery/dist/jquery.min.js"]
  },
  "rootDirs": ["src","out"], // 将多个目录放在一个虚拟目录下,用于运行时,即编译后引入文件的位置可能发生变化,这也设置可以虚拟src和out在同一个目录下,不用再去改变路径也不会报错
  "listEmittedFiles": true, // 打印输出文件
  "listFiles": true// 打印编译的文件(包括引用的声明文件)
}


#【第三篇:基础类型】

#数据类型

ts是js的超集,包含js所有的数据类型;并拓展了一些类型。

ts是静态类型,类型是确定的,一旦赋值之后不可随意更改;
js是动态类型,类型是不确定的,赋值之后也可随意更改。

  • js数据类型

    • 基础数据类型:boolean、number、string、null、undefined、symbol
    • 引用数据类型:object
  • ts数据类型

    • boolean、number、string、null、undefined、symbol
    • object
    • any、void、never
    • 元组、数组
    • 枚举(enum)、接口(interface)
1. 布尔值 (boolean)
let bool: boolean = true;
2. 数字 (number)

支持整数、浮点数,支持十进制、十六进制、八进制、二进制

let num: number = 66;
let num2: number = 0.99;
3. 字符串 (string)

支持模板字符串

let str: string = 'hello world';
//模板字符串
let age: number = 24;
let Name: string = 'Tom';
let word: string = `my name is ${Name}, 明年我就${age + 1}岁了`;
4. null 、undefined
  • 默认情况下是除never类型之外所有类型的子集,包括数组、元祖等;
  • 严格模式下:开启--strictNullChecks
    null能赋值的类型有:any、null
    undefined 能赋值的类型有:any、undefined、void
/* 默认情况下 */

//赋值给数组
let arr: number[] = null;
arr = undefined;

//赋值给元祖
let yy:[boolean, string] = undefined;
yy = null;

/* 严格模式下 */
//以上会报错,以下三种是正确的。
let nu: null = null;
let un: undefined = undefined;
let vo: void = undefined;
5. object
  • object表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型。
  • 上面是说的严格模式,非严格模式下null、undefined是object的子集。
  • 另外,虽然在js中,typeof null === object,但是在严格模式下,null不能赋值给object的类型。
/* 严格模式 */
let obj: object = []; // 正确
obj = null; // 不能将类型“null”分配给类型“object”
6. any

表示任意类型
注意:① any其实是移除类型检查,在对现有代码进行改写的时候非常有用;② 使用any移除类型检查,显然违背了ts的初衷;另外使用any会丢失一些信息,让类型推论变得诡异;除非特殊情况,不建议使用any

let an: any = 123;
an = true;
an = [1,2];
7. void
  • 表示没有任何类型,一般用于表示函数没有任何返回值;
  • 约束变量时,只能赋值:<默认>undefined、null,<严格>undefined
function ff(): void {
    console.log('我没有返回值');
}
8. 元组

元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。

let arr:[number, string] = [12]; //错误,少元素
let arr:[number, string] = [12, 'aa', true]; //错误,多元素
let arr:[number, string] = [true, 'aa']; //错误,类型不对

let arr:[number, string] = [123, 'aa']; //正确
9. 数组

TypeScript像JavaScript一样可以操作数组元素;有三种方式可以定义数组。

  • 第一种:元素类型 + [ ]
  • 第二种:使用数组泛型,Array<元素类型>
  • 第三种:使用接口interface
//第一种
let arr: number[] = [];
//第二种
let arr2: Array<number> = [];
//第三种
interface Iarr {
    length: number;
    [index: number] : number;
}
let  arr3: Iarr = [];
  • 使用的类型元素,可以是任意元素类型,包括interface定义的类型;
//数字
let arr: number[] = [];
//null、undefined或void,但是没有多少意义
let arr: null[] = [null];
//数组
let arr: string[][] = [ ['a'] ];
//接口
interface Ia {
    name: string
}
let arr: Ia[] = [ { name: 'Tom' } ];


#【第四篇:高级类型】

#类型注解

我们手动为变量声明类型,就是类型注解。

//声明num的类型是number
let num:number;
num = 123;

#类型推论

(1) 如果你没有对变量进行注解,ts会根据赋值自动进行推论。如果一个变量的类型,ts会自动推论出,则可以不进行类型注解。
(2) 类型推论帮助我们保持代码精简和高可读性。

  • 如果一个变量只声明,未注解,未赋值,则推论为any
let nn; // => let nn: any;

nn = 123;
nn = true;
nn = 'string';
  • 函数的形参,未注解,则推论为any
function ff(n) { // => n: any
  console.log(n)
}
  • 一个变量,未注解,但是赋值了,则推论为所赋值的类型 (除null、undefined)
  • 若被赋值的是null或undefined,则推论为any
let n = 123;        // => let n: number = 123;

//null或undefined
let nu = null;      // => let nu: any = null;
let un = undefined; // => let un: any = undefined;
1. 类型推论的应用
//有一个函数表达式如下:
let ff: (pram1: number, pram2: string) => number = function(a: number, b: string): number {
  return a
}

//其实已经对变量ff进行注解了,ts能够推论出后面的function的类型
//可以简化如下:
let ff2: (pram1: number, pram2: string) => number = function(a,b) {
  return a;
}

//当然,使用interface还可以简化:
interface Ifn {
  (pram1: number, pram2: string) : number;
}
let ff3: Ifn = function(a, b) {
  return a;
}

#联合类型

联合类型(Union Types)表示一个值可以是几种类型之一; 使用竖线 | 分隔每个类型;类型可以是任何的类型,包括interface创建的类型等。

/* 基础类型 */
let nn: number|string|boolean;
nn = 123;
nn = 'hello';
nn = true;

/* interface创建的类型 */
interface Itp {
  name: string
}

let mm: number|Itp;
mm = 123;
mm = { name: 'Tom' };

联合类型使用成员共有属性或方法不会报错;但是如果使用了非共有的属性,则会根据类型推论在赋值时判断。

/* 函数中如下写,一定会报错;可以使用类型断言,见下: */
function fn(param: number|string):number {
  return param.length;  //报错,类型“string | number”上不存在属性“length”
}

/* 根据赋值情况来判断是否正确 */
let nn: number|string;
nn = 'abc';
console.log(nn.length); //不报错
nn = 123;
console.log(nn.length); //报错, 类型“number”上不存在属性“length”

#类型断言

类型断言(Type Assertion)可以用来手动指定一个值的类型。经常与联合类型一同使用。

  • 语法一:<类型>值
  • 语法二:值 as 类型
    在 tsx 语法(React 的 jsx 语法的 ts 版)中必须使用值 as 类型
function ff(param:number|string):number {
  return (<string>param).length;
  //或者
  return (param as string).length
}

#类型别名

类型别名就是给某个类型或联合类型起一个新的名字;起到简化的作用;使用关键字type定义类型别名;类型可以是任何的类型,包括interface创建的类型等。

//把 number 取名为 Tnum
type Tnum = number;
let nn: Tnum = 123;

//为联合类型取名为 Tuni
type Tuni = number | string | boolean;
let mm: Tuni = 123; //等同于:let mm: number|string|boolean = 123;
mm = 'hello';

//联合类型中有interface创建的类型,取名为 Tinter
interface Iobj {
  name: string
}
type Tinter = number | Iobj;
let vv: Tinter = 123;
vv = { name: 'Tom' };
1. 类型别名与接口的区别
  • 类型别名可以理解为对联合类型的简化写法,本身不创建新的类型,也不能 extends和 implements其它类型;
  • 而接口是创建一个新的类型,能 extends和 implements其它类型;


#【第五篇:检查赋值】

ts的核心就是类型检查,学过js的我们都知道这个类型可以是 boolean、string、number等等;但是ts不仅可以约束所赋值的数据类型,还可以对所赋的值进行约束。

其实不论是具体的数据类型还是具体的值,在ts中都叫做类型检查;只是我们不是很理解罢了,总之能使用数据类型的地方也能使用具体的值(我没全部测试,我觉得应该是);测试如下:

//sex变量只能赋值 男
let sex: '男';
sex = '男';
sex = '女'; //错误

(1) 使用联合类型

let sex: '男'|'女'|'保密';

(2) 使用类型别名

type show = '优秀' | '良好' | '及格' | '很差';

let d: show = '优秀';

(3) 使用interface

interface Istr {
  name: 'Tom' | 'Mike' | 'Leo',
  work: '优秀' | '良好' | '及格' | '很差'
}

//使用
let person1: Istr = {
  name: 'Mike',
  work: '优秀'
}

let person2: Istr = {
  name: 'Tom',
  work: '及格'
}


# 【第六篇:接口(interface)】

TypeScript的核心原则之一是对值所具有的结构进行类型检查。我们可以使用boolean、number、string等对一个普通变量进行检查。

let boo: boolean = true;
let num: number = 123;
let str: string = '456';

但是,如果我们需要一个对象,里面必须有name、age属性,并且name是string类型,age是number类型;那我们上面的方法就无法实现如此复杂的操作了,此时我们可以使用interface来定义一套检查规范。

interface可以理解为自定义的类型规范,可以同string、number等一样使用。

//定义接口
interface Itype {
  name: string,
  age: number
}
//使用接口进行类型检查
let t: Itype = {
  name: 'Tom',
  age: 25
}

其实像boolean、number、string等其实是一种简单类型检查规范,interface能将这些简单的规范组合在一起,定义更加复杂的规范。

1. 对象类型的接口

接口可以定义一类对象的形状(即属性或方法);变量对象的形状必须与接口的形状保持一致,即属性名、属性类型、所有属性一一对应。接口可以定义必选属性、可选属性、只读属性、任意属性;

  • 必选属性
interface Imust {
  name: string
}

//定义的变量对象必须有值是string类型name属性,且不允许有其他属性
let prop: Imust = {
  name: 'Tom'
}
  • 可选属性
interface Ichoice {
  name : string,
  age? : number //可选属性
}


//定义变量对象 -- 无age属性
let prop: Ichoice = {
  name: 'Tom'
}
//定义变量对象 -- 有age属性
let prop2: Ichoice = {
  name: 'Tom',
  age: 23
}
  • 只读属性
interface Iread {
  name: string,
  readonly sex: string //只读属性
}

//定义的变量对象中的sex属性只能读取,不能重新赋值
let prop: Iread = {
  name: 'Tom',
  sex: '男'
}
prop.sex = '女'; //报错
  • 任意属性
interface Iany {
  [propName: string]: boolean
}
/* 
  propName:代指属性名,取值任意,但尽量语义化
  [string]:指定变量对象的属性名的类型是字符串类型
  boolean: 指定变量对象的属性值的类型是布尔类型,【A】

  注意:这种写法不是只能赋值一个属性,而是可以赋值n个属性;可以理解为正则匹配
*/
let obj: Iany = {
  a: true,
  b: false
}


//注释A处,这里的类型可以是任何类型
//但是,一些必须属性的类型能限制它的类型,如下
interface Iany2 {
  name: string,
  [propName:string]: //B
}
//B处只能选择 string或any,因为 propName 可能是 name
//而name只能赋值string类型的值,而不能赋值其他类型的值

(2) 使用任意属性来约束数组

//使用接口能约束数组,但是也可能是伪数组
interface Iarr {
  length: number,
  [index: number]: boolean
}

//数组
let arr: Iarr = [true, false];
//伪数组
let obj: Iarr = {
  length: 2,
  0: false,
  1: true
}
2.函数类型的接口

为函数表达式的变量添加约束。

interface Ifn {
  (pram1: string, pram2: number) : boolean;
}
/* 
  + pram1、pram2单纯为了指定赋值的函数体的形参数量和数据类型;在赋值的函数体中的形参名是自定义的
  + 表示函数体中最多有2个形参,且参1必须是string类型,参2必须为number类型
  + 若参数没有指定形参的类型,则默认参1为string类型,参2为number类型
  + 可以不传参数或只传一个参数

  + boolean处为指定函数体的返回值,若非any、void类型或不填,则必须指定函数体的该类型的返回值

  + 遵循严格模式 --strictNullChecks
*/

//指定返回值,无形参
let f1: Ifn = function(): boolean {
  return true;
}
//指定返回值,一个形参
let f2: Ifn = function(name: string): boolean {
  return true;
}
//指定返回值,2个形参,但不指定类型
let f3: Ifn = function(name, age): boolean {
  return true;
}
3.接口的继承 (extends)
interface Ia {
  name: string
}
//Ib接口继承Ia接口
interface Ib extends Ia {
  age: number
}

//定义变量对象
let n: Ib = {
  name: 'Tom',
  age: 24
}


#【第七篇:函数注解】

1. 函数声明式
function getBar(name: string, age: number): string {
    return `My name is ${name}, ${age}岁了!`
}
//调用时,需要让参数的类型和数量保持一致,否则会报错
getBar('Tom', 25);
2. 函数表达式
/* 第一种:只注解函数 */
let getBar = function(name:string, age:number):string {
    return name + age;
}
getBar('Tom', 34);

/* 第二种:全部注解 */
let getBar2: (param1:string, param2: number) => string = function(name:string, age:number): string {
    return name +  age;
}
getBar2('Tom',66);

/* 第三种:根据类型推论,第二种可以简写如下: */
let getBar3: (param1:string, param2:number) => string = function(name,age) {
    return name + age;
}
getBar3('Tom',66);

/* 第四种,将变量左边用interface简化 */
interface Ifn {
    (param1:string, param2:number) : string;
}
let getBar4:Ifn = function(name,age) {
    return name + age;
}
getBar4('Tom', 88);

(1) 函数表达式的函数变量说明:

let getFoo: (param1:string, param2: number) => string;
/*
  getFoo的值必须是一个函数,
  该函数可以有0-2个参数,参数名自定义,
  参数的类型第一个必须是string,第二个必须是number,
  返回值是string
*/

(2) 使用联合类型时,需要使用 () 括起来,否则会出错

//表示函数或number类型
let obj: ( (param:string) => string ) | number;

(3) 函数调用时,所传的参数数量和类型必须跟function注解时的数量和类型一致,否则会报错。

3. 默认参数
function fn(name = 'Tom'): string {
    return name;
}
4. 可选参数

ts里的每个函数参数都是必须的;但是在js里,每个参数都是可选的,可传可不传;在ts里我们可以在参数名旁使用?实现可选参数的功能。
注意:① 可选参数必须放到必须参数之后;② 可选参数不能使用默认参数

function getBar(name: string, age?: number): string {
    return name;
}
//调用
getBar('Tom');
getBar('Tom', 24);

5. 剩余参数

注意:剩余参数变量是数组类型

function getFoo(a:string, b?: number, ...args:any[]):void {
    console.log(a); //aaa
    console.log(2); //2
    console.log(args); //[ 3, 4, 5 ]
}

getFoo('aaa',2,3,4,5);

6. 重载

重载就是让代码看着更清楚,语意更明确而已

function sum(n: number): number;
function sum(n: string): string;
function sum(n: number|string): number|string {
    if(typeof n === 'number') {
        return n + 99;
    }else{
        return n + 'Hello World!'
    }
}

console.log(sum(1)); //100
console.log(sum('Tom_')); //Tom_Hello World!


[TOC]


# 【第八篇:class】

1. 实例私有属性、方法

注解实例私有属性、方法需要先在class内部声明;

class Person {
  name: string; //注解实例私有属性
  say: () => void; //注解实例私有方法

  constructor(name: string) {
    this.name = name;
    this.say = function() {
        console.log('My name is', this.name)
    }
  }
}

let p = new Person('Tom');
p.say();
2. 继承

继承来的属性或方法不需要在class内部进行注解了。

/* 父类 */
class Person {
  name: string;

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

/* 子类 */
class Man extends Person {
  //name:string; //这里的name是不需要注解的,因为这是从父类继承过来的
  age:number;    //这里的age是自己的属性,需要进行注解

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

let m = new Man('Tom',55);
console.log(m);
3. 只读修饰符
class Person {
  readonly name:string;
  constructor(name:string) {
    this.name = name;
  }
}

let p = new Person('Tom');
p.name = 'Mike'; //无法分配到 "name" ,因为它是只读属性
4. 公共,私有与受保护的修饰符

(1) ts规定class成员有三种修饰符,public、protected、private;默认是public
(2) public:当前类内部,子类内部,实例对象均可使用
(3) protected:当前类内部,子类内部可使用,实例对象均不可使用
(4) private:仅在当前类内部可以使用,子类,实例对象均不可使用

注意:① 在实例对象中使用了private修饰的属性,也仅仅是在ts中提示错误,仍然能正确编译成js
② ts中的private与es6中的 # 是有本质区别的;但是如果遵循ts的错误提示,是可以起到相同作用的。

  • public
/* 父类 */
class Person {
  public name: string;

  public constructor(name:string) {
    this.name = name;
  }

  public perSay() {
    console.log('public属性:name',this.name);
    
  }
}

/* 子类 */
class Man extends Person {
  public constructor(name:string) {
    super(name);
  }

  public manSay() {
    console.log('继承父类的public属性:name',this.name);
  }
}

//父类实例化
let p = new Person('Tom');
console.log(p.name); //正常
p.perSay(); //正常

//子类实例化
let m = new Man('Mike');
console.log(m.name); //正常
m.manSay(); //正常
  • protected
/* 父类 */
class Person {
  protected name: string;  //name属性是受保护的

  public constructor(name:string) {
    this.name = name;
  }

  public perSay() {
    console.log('protected属性:name',this.name);
    
  }
}

/* 子类 */
class Man extends Person {
  public constructor(name:string) {
    super(name);
  }

  public manSay() {
    console.log('继承父类的protected属性:name',this.name);
  }
}

//父类实例化
let p = new Person('Tom');
console.log(p.name); //错误,父类实例不能访问
p.perSay(); //正常

//子类实例化
let m = new Man('Mike');
console.log(m.name); //错误,子类实例不能访问
m.manSay(); //正常,manSay方法是使用的子类Man内部的name属性

  • private
/* 父类 */
class Person {
  private name: string;  //name属性是私有的

  public constructor(name:string) {
    this.name = name;
  }

  public perSay() {
    console.log('private属性:name',this.name);
    
  }
}

/* 子类 */
class Man extends Person {
  public constructor(name:string) {
    super(name);
  }

  public manSay() {
    console.log('继承父类的private属性:name',this.name); //错误,见下
  }
}

//父类实例化
let p = new Person('Tom');
console.log(p.name); //错误,父类实例不能访问
p.perSay(); //正常,父类内部可以访问

//子类实例化
let m = new Man('Mike');
console.log(m.name); //错误,子类实例不能访问
m.manSay(); //错误,子类不能使用

5. 静态属性、静态方法
class Person {
  static isNa = '静态属性';

  static isRead = function() {
    console.log('静态方法', Person.isNa);
  }
}
Person.isRead()
6. 抽象类

抽象类做为其它派生类的基类使用;不能直接被实例化。

abstract class Person {
  name: string;
  constructor(name) {
    this.name = name;
  }
}

let p = new Person('Tom'); //无法创建抽象类的实例。


#【第九篇:泛型】

(1) 当我们写好一个API后,不仅需要支持当前的数据类型,同时也能支持未来的数据类型;泛型就给予了这样的灵活性。
(2) 当我们定义接口或类时,如果遇到数据类型不明确时,就可以使用泛型。

//无复用性,只能传入number类型
function foo(arg:number): number {
    return arg;
}
foo(123);

//使用any虽然实现了复用性;[本质上是移除类型检查]
//但是我们只知道可以传入任意类型参数,也会返回任意类型值
//但是不能保证传入的参数与返回的值类型相同
//比如我们传入一个数字,我们只知道任何类型的值都有可能被返回
//这样让整个api变得诡异,不建议使用any
function foo2(arg:any): any {
    return arg;
}

//此时我们就可以使用泛型
function foo3<T>(arg: T): T {
    return arg
}
1. 如何定义泛型

定义泛型是使用尖括号, <类型变量>,类型变量是一种特殊的变量,只用于表示类型而不是值;类型变量是自定义名,但一般使用大写字母。

2. 函数中使用泛型
  • 定义泛型
    可以定义一个泛型,也可以定义多个泛型。
//定义一个泛型 
//泛型是 T, 参数arg类型是T, 返回值类型是T
function foo<T>(arg: T): T{
    return arg;
}

//定义多个泛型
//泛型是T、K, 参数name类型是T、age类型是K, 返回值类型是K
function bar<T, K>(name:T, age:K): K {
    return age;
}
  • 使用泛型
    可以使用尖括号(< >)来明确地传入类型,也可以使用类型推论而省略;
function foo<T>(arg: T): T{
    return arg;
}

//传入类型
let out = foo<string>('Hello');
//使用类型推论
let out2 = foo('World');
  • 使用泛型变量,把泛型当做类型的一部分,Array<T>
//定义了泛型T,参数names类型是泛型T的数组,返回值类型是number
function getLen<T>(names:Array<T>): number {
    return names.length;
}
3. 类中使用泛型
//Person类中定义泛型T
//实例属性使用泛型T
class Person<T> {
    name: T;
    constructor(name:T) {
        this.name = name;
    }
}

//传入类型
let p = new Person<string>('Tom');
//不传入类型
let p2 = new Person(123);
4. 接口中使用泛型

接口中使用泛型与其他最大的区别就是,需要使用尖括号(< >)来明确地传入类型。

interface Inter<T>{
    (param: T): T;
}

//使用时,必须传入类型
let ff:Inter<string> = function(name) {
    return name;
}
5. 泛型约束

我们也可以为泛型增加相应的约束,比如我们希望传入的参数必须有length属性,如下实现:

interface Iarr {
    length: number
}

function getLen<T extends Iarr>(names: T):number {
    return names.length
}

//使用
getLen(123); //报错,数字没有length属性
getLen('Hello'); //ok


# 【第十篇:枚举 enum】

(1) 枚举是ts对js标准数据类型的拓展,枚举是只读属性
(2) 我们在对接后台时,常常会遇到这样的场景,当请求数据时 0:fail, 1:success, 2:error,此时就可以使用枚举。

enum s {
  fail = 0,
  success = 1,
  error = 2
}
1. 数字枚举

(1) 数字枚举默认从0开始,依次递增

//上面的例子等同于
enum s {
  fail = 0,
  success = 1,
  error = 2
}

(2) 数字枚举赋值的变量下面依次递增

enum s {
  fail,
  success = 20,
  error
}
//等同于
enum s {
  fail = 0,
  success = 20,
  error = 21
}

(3) 可以使用外部变量或函数,但是下面的值需要赋初始值

function getNum():number {
  return 11;
}

enum s {
  fail = getNum(),
  success, //枚举成员必须具有初始化表达式
  error
}

//修改如下:
function getNum():number {
  return 11;
}

enum s {
  fail = getNum(),
  success = 1, 
  error
}

(4) 数字枚举是反向映射的,即你可以通过属性名找到值,也可以根据值找到属性名

enum s {
  fail = 0,
  success = 1,
  error = 2
}
console.log(s.success); // 1
console.log(s[1]);      // success
2. 字符串枚举

(1) 字符串枚举没有默认值,也不会自增;必须手动赋初始值。

enum s {
  fail = 'fail',
  success = 'success',
  error = 'error'
}

(2) 字符串枚举没有反向映射

enum s {
  fail = 'f',
  success = 's',
  error = 'e'
}

console.log(s.fail); // f
console.log(s.f);    // 类型“typeof s”上不存在属性“f”
3. 异构枚举

异构枚举就是一个枚举类型中既有数字枚举,也有字符串枚举;官网不推荐使用异构枚举。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • 为什么要使用TS? 获得更好的开发体验,解决JS中一些难以解决的问题 JS存在的问题: 使用了不存在的变量函数或者...
    小丹子1o1阅读 663评论 0 0
  • TypeScript 是 JavaScript 的一个超集,主要提供了类型系统和对 ES6 的支持,它由 Micr...
    Gukson666阅读 8,638评论 3 29
  • 环境搭建 npm i typescript -g只需要安装一次 tsc --init会生成tsconfig.jso...
    强某某阅读 654评论 0 0
  • 1.TS概述 1.1 TS相比于js的优势: 优势一:类型化思维方式,提前发现错误,减少改bug时间;优势二:提高...
    洛珎阅读 388评论 0 0
  • 一、安装 全局安装typescript(默认你已经安装了node) npm install -g typescri...
    小美人鱼失去的腿阅读 541评论 0 0