TypeScript学习笔记

TS 安装

npm i -g typescript

tsc index.ts 会将ts文件编译成对应的js文件

创建tsconfig.json文件

<!-- 生成配置文件 -->
tsc --init
<!-- 修改输出目录 -->
"outDir": "./js"
<!-- 配置自动ts转js -->
终端 配置任务  监视tsconfig
终端 运行任务  监视tsconfig

基本数据类型

  • 布尔类型 boolen
  • 数字类型 number
  • 字符串类型 string
  • 数组类型 array
  • 元组类型 tuple
  • 枚举类型 enum
  • 任意类型 any
  • null和 undefined
  • void类型
  • never类型
<!-- 数组的两种定义方式 -->

var arr: number[] = [1,2,12]

var arr:Array<number> = [1,2,111]

<!-- 元组类型  属于数组的一种 -->
> 给数组中每一个位置指定对应的类型

let arr:[number, string] = [123,'ssss']

<!-- 枚举类型 -->
> 标识符不赋值的话 值为其下表
enum Flag {
  success = 1,
  error,
  'normal'
}

let s:Flag = Flag.success
let e: Flag = Flag.error
let n: Flag = Flag.normal
s => 1
e => 1
n => 2

<!-- 任意类型的用处 -->
var box:any = document.getElementById('box');
box.style.color='red'

<!-- null undefined -->
> 其他类型(never类型)的子类型

var num:number | null | number;

<!-- never类型 -->
> 是其他类型 包括null 和undefined 的子类型 代表从不会出现的值
> 一位置never类型的变量只能被never类型所赋值

函数

function run (name:string , num?:number=20, ...result:number[] ): void {

}

? 表示可选参数,要放到必传参数的后面 

<!-- 函数的重载 -->
> 为同一个函数提供多个函数类型定义来实现多种功能的目的

function getInfo (name: string): string;
function getInfo (age: number): string;
function getInfo (str:any):any {
  if (typeof str === 'string) {
    return '我叫' + str;
  } else {
    return '我的年龄' + str;
  }
}

ES5中的继承通过原型链继承和对象冒充继承来实现
两个同时用才能实现需求

function Son (name, age) {
  Person.call(this, name, age) // 对象冒充继承 可以继承构造函数里面的属性和方法, 但是不能继承原型链上的属性和方法
}

Son.prototype = Person.prototype // 原型链继承可以继承父类方法但是不能传参

ES5中的静态属性和方法
> 可以直接通过类名调用
Son.name = 'jack'
Son.run = function() {}

ES5中的实例属性和方法
写在类中,通过new出的实例调用的

TS中的类

class Person {
  name: string; // 属性 前面省略了public关键字
  constructor (n: string) {
    this.name = n
  }
  getName (): string {
    return this.name
  }
  setName (name: string): void {
    this.name = name
  }
}

let p = new Person('a')
console.log(p.getName) => a
p.setName('b') 
console.log(p.getName) => b

TS中的继承

class student extends Person {
  constructor(name:string) {
    super(name) // 初始化父类的构造函数
  }
}

类中修饰符

  • public
  • private 只能在当前类使用
  • protected 受保护的:只能在当前类和子类中访问, 不能通过实例访问

静态方法

class Person {
  name: string; // 属性 前面省略了public关键字
  static: age: number = 20; // 静态属性 可以通过类名直接访问
  constructor (n: string) {
    this.name = n
  }
  getName (): string {
    return this.name
  }
  setName (name: string): void {
    this.name = name
  }

  static run():viod { // static修饰的静态方法 直接通过类名调用,不能直接调用类里面的属性,但是可以调用静态属性
  }
}

多态

父类定义一个方法 在子类中实现,每个子类有不同的表现

抽象方法抽象类

抽象类: 提供其他类继承的基类, 不能直接被实例化
使用abstract关键字定义抽象类和抽象方法
抽象类中的抽象方法不包含具体实现, 必须在派生类中实现
abstract抽象方法只能放在抽象类中

abstract class Animal {
  name:string;
  constructor (name:string) {
    this.name = name
  }
  abstract eat():any; 
}

class Dog extends Animal {
  constructor (name:string) {
    super(name)
  }
  // 抽象类的子类必须实现抽象类里面的抽象方法
  eat () {
    console.log(this.name+'eat')
  }
}

接口

用于规范的定义

  1. 对象的约束 属性接口
interface FullName {
  firstName: string;
  secName: string;
}

function printName (name: FullName) {
  // 必须传入name并且格式必须满足FullName
  console.log(name.firstName, name.secName)
}
let obj = { // 传入的参数必须包含 批量验证会报错 建议严格按照接口要求
  age: 20,
  firstName: 'jack';
  secName: 'ma';
}
printName(obj) 

printName({ 
  age: 20, // 此时会报错
  firstName: 'jack';
  secName: 'ma';
}) 

<!-- 可选属性 -->
interface FullName {
  firstName: string;
  secName?: string; // 加? 可传可不传
}

  1. 函数类型接口:对方法传入的参数 以及返回值进行约束
interface encrypt {
  (key:string, value:string): string;
}
let md5:encrypt = function(key:string, value:string): string {
  return key+value
}
  1. 可索引接口: 数组,对象的约束 (不常用)
<!-- 对数组的约束 -->
interface UserArr {
  [index:number]: string;
}
let arr: UserArr = ['aaa','bbb'];
console.log(arr[0])
<!-- 对对象的约束 -->
interface UserObject{
  [index:string]:string
}
var obj:UserObject = {name: 'kaka'}
  1. 类 类型接口 对类的约束
interface Animal {
  name:string;
  eat (str:tring):void;
}

class Dog implements Animal {
  name:string;
  constructor(name:string) {
    this.name = name;
  }
  eat () {
    console.log(this.name)
  }
}

let d = new Dog('wangwang')
  1. 接口的扩展
interface Animal {
  eat():void;
}

inetrface Person extends Animal {
  work():void;
}

Class Studet implements Person {
  name: string;
  constructor (name:string) {
    this.name = name;
  }
  eat () {
    
  }
  work () {

  }
}

泛型

可以支持不特定的数据类型
具体什么类型是调用这个方法的时候决定的

function getData<T>(value:T):T {
  return value;
}

getData<number> (123);

getData<string> ('ja');

类的泛型

class MinClass<T> {
  public list:T[] = [];
  add(value:T):void {
    this.list.push(value);
  }
  min():T {
    var minNum = this.list[0];
    this.list.forEach(e => {
      if(minNum>e) {
        minNum = e
      }
    })
    return minNum
  }
}

let m1 = new MinClass<number>(); // 实例化类 并且指定了T代表的类型是number
let m2 = new MinClass<string>();

泛型接口


interface ConfigFn {
  <T>(value:T):T;
}

let getData:ConfigFn = function<T>(value:T):T{
  return value;
}

getData<string>('jack')
getData<number>(11122)

interface ConfigFn {
  <T>(value:T):T;
}

function getData<T>(value:T):T {
  return value
}

var myGetData:configFn<string>=getData;

myGetData('www')

泛型类

将类作为泛型 用于约束

class User {
  name: string| undefined;
  pwd: string| undefined;
}

class MysqlDb<T> {
  add(user:T): Boolean {
    return true
  }
}

ley u = new User();
u.name='a';
u.pwd='pwd';

let Db = new MysqlDb<User>();
Db.add(u);

综合案例

定义一个操作数据库的库, 支持mysql mssql mongodb
要求

  • 都有增删改查
  • 约束同意规范 代码重用
// 1. 首先制定一个接口

interface DBI<T> {
  add(info:T):boolean;
  update(info:T, id:number):boolean;
  delete(id:number):boolean;
  get(id:number):any[];
}

// 2. 定义一个操作mysql数据库的类 注意:要实现泛型接口 这个类也应该是一个泛型类

class MysqlDb<T> implements DBI<T> {
  add(info: T): boolean {
    console.log(info)
    return true;
  }  update(info: T, id: number): boolean {
    console.log(info,id)
    return true;
  }
  delete(id: number): boolean {
    console.log(id)
    return true;
  }
  get(id: number): any[] {
    console.log(id)
    return [];
  }
}

// 3.mssql 的

class Mssql<T> implements DBI<T> {
  add(info: T): boolean {
    console.log(info)
    return true;
  }  update(info: T, id: number): boolean {
    console.log(info,id)
    return true;
  }
  delete(id: number): boolean {
    console.log(id)
    return true;
  }
  get(id: number): any[] {
    console.log(id)
    return [];
  }
}

// 4.  操作

class User {
  name: string | undefined;
  pwd: string | undefined;
}

let u = new User();
u.name = 'jack';
u.pwd ='sssss';
//  将类作为泛型的类型校验
let oMysql = new MysqlDb<User>();
let oMssql = new Mssql<User>();
oMysql.add(u)
oMssql.add(u)

命名空间

namespace

装饰器

通俗的讲装饰器就是一个方法,可以注入到类,方法,属性或参数上来拓展类,属性,方法和参数的功能。

类装饰器

  1. 类装饰器--不传参
function logClass(params:any) {
  // params:当前的类
  params.prototype.apiUrl = '动态拓展的属性'
  params.prototype.run = function() {
    console.log('一个方法')
  }
}

@logClass
class Http {
  constructor () {}
  getData () {}
}

let httpClient:any = new Http();
console.log(httpClient.apiUrl) => '动态拓展的属性'

httpClient.run()

  1. 类装饰器--接受传参 (装饰器工厂)
function logClass(params:string) {
  // params:当前的类
  return function (target:any) {
    console.log(target)
    console.log(params)

    target.prototype.apiUrl = params;
  }
}

@logClass('www.baidu.com')
class Http {
  constructor () {}
  getData () {}
}

let httpClient:any = new Http();
  1. 重载构造函数
function logClass(target: any) {
  return class extends target {
    name:any = '修改后的name';
    getData () {
     this.name = this.name + '----'
    }
  }
}

@logClass
class Http {
  public name:string|undefined
  constructor () {
    this.name = 'name 1'
  }
  getData () {
    console.log(this.name)
  }
}

let httpClient:any = new Http();
httpClient.getData()

属性装饰器

属性装饰器表达式会在运行时当做函数被调用,传入下列两个参数

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  2. 成员的名字
function logProperty(params:string) {
  return function (target: any,attr: any) {
    // 这里target 及 attr 分别是构造函数和修饰的属性
    console.log(target, attr)
    target[attr] = params // 修改为穿过来的参数
  }
}

class Http {
  @logProperty('name 2')
  public name:string|undefined
  constructor () {
    this.name = 'name 1'
  }
  getData () {
    console.log(this.name)
  }
}

let httpClient:any = new Http();
httpClient.getData()

方法装饰器

会被应用到方法的属性描述上 可以用来监视 修改或者替换方法定义
运行时回传入下列3个参数

  • 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  • 成员的名字
  • 成员的属性描述符

方法参数装饰器

会在运行时当做函数被调用,可以使用参数装饰器为类的原型增加一些元素数据
传入下列三个参数

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

推荐阅读更多精彩内容