Typescript 学习笔记

数据类型

// ---------- 布尔类型(boolean): true/false---------
let flag:boolean = true;
// flag = ‘’ 错误
// ---------- 数字类型(number)-------------------
let a:number = 123;
// a = true 错误写法
// a = 10.1 正确

// ---------- 字符串类型(string)---------------
let str:string = “hello”

// ---------- 数组类型(array) ts 中定义数组有两种方式----------
// 第一种定义数组的方式,每个元素类型都必须一致
let arr:number[] = [1,2,3,4,5]
// 第二种定义数组的方式
let arr2:Array = [12.0,12,15,16]
let strArr:Array = [“12”,“hello”]

// ---------- 元组类型(tuple) 属于数组的一种--------
let arr3:[string, boolean, number] = [‘hei’, true, 10]

// ---------- 枚举类型(enum)--------
/**

  • enum 枚举名 {
  • 标识符[=整型常数]
  • 。。。
  • }

*/
enum Flag {success=1,error=-1}
let f:Flag = Flag.error
console.log(f)
enum Color { red, blue, orange}
let c:Color = Color.blue
console.log©// 1 默认不给值的话就会打印对应的索引值

// ---------- 任意类型(any)--------------
let anyNum:any = 123;//正确
anyNum = “hahah”//正确
// 使用,通常用在 获取元素节点的时候,节点为对象类型,但是基本数据类型中没有object,所以此时可以将节点元素变量定义为 any 变量

// ---------- null 和 undefined 其他(never类型) 数据类型的子类型 -----------
let aj:number | undefined;
console.log(aj)

let b:null;
// ---------- void 类型, typescript 中的void 表示没有任何类型,一般用于定义方法没有返回值----------
// 表示该方法没有返回值
function fun():void {
console.log(“fun”)
}
fun();
// 如果方法有返回值, 方法加上返回值的类型
function fun2():number {
return 123
}
fun2();

// ---------- never 类型: 是其他类型(包括 null 和 undefined)的子类型,代表从不会出现的值
// 这意味着声明 never 的变量只能被 never 类型所赋值
let yy:never

typescript 中的函数

// 1、函数的定义

//----ES5
// // 函数声明式
// function run() {
// return “12”
// }
// //匿名函数
// let run2 = function(){
// return ‘154’
// }

//–TS中定义
// 函数声明法
function run3():string {
return “111”
}
// 匿名函数
let func2 = function():number {
return 110
}
// ts 中定义方法传参

function getInfo(name:string, age:number):string {
return ${name}----->${age}
}

// 方法可选参数(关键字式问号?)
//es5中的方法的实参和形参可以不一致,但是ts中必须一样,如果不一样就需要进行配置可选参数
function getInfo2(name:string, age?:number):string {
return ${name}----->${age}
}
//注意: 可选参数必须配置到参数的最后面,由于可以不传,放在方法的前面会导致参数有问题

//默认参数
// es5 里面没法设置默认参数, ts 中可以设置默认参数
function getInfo3(name:string, age:number=30):string {
return ${name}----->${age}
}

// 剩余参数( 三点运算符,接收形参传过来的值)
function sum(a:number,b:number,c:number,d:number):number{
return a+b+c+d
}
// 三点运算符,接收形参传过来的值
function sum2(…result:number[]):number{
let total = 0;
result.forEach((it)=>{
total+=it
})
return total
}
sum2(1,2,3,4,5,6,7,8,9,10)

// 函数的重载
// java中方法的重载,重载指的是两个或者两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况
//JavaScript中的重载,通过为同一个函数提供多个函数类型定义来试下多种功能的目的
//ts为了兼容 es5以及 es6重载的写法和java 中有区别
/**

  • es5 中css定义同名函数,后面 一个方法会覆盖前面一个方法
    */

/**

  • ts 中的重载
  • function getInfo4(name: string):string;
  • function getInfo4(name: number):number;
    */
    function getInfo4(name: number):string;
    function getInfo4(name: string):string;
    function getInfo4(str: any):any{
    if(typeof str ===‘string’){
    return 我叫,${str}
    } else {
    return 我的年龄是${str}
    }
    }

// 箭头函数, this 的指向是上下文

typescript 中的类

// es5中的类,使用构造函数进行定义,使用 new 关键字进行实例化后调用.构造函数和原型链里面增加方法
// 原型链上面的属性会被多个实例共享,构造函数不会
// 静态方法不需要实例化

//es5 里面的继承
//原型链+对象冒充的组合继承模式
//Person.call(this) //对象冒充实现继承,可以继承构造函数中的属性和方法,但是无法调用原型链中的对象和方法
// 原型链实现继承,也可以继承构造函数和原型链中的对象和方法.
// 原型链继承的问题: 实例化子类的时候不能给父类传参
/**

  • es5
  • function Person(name) {
  • this.name = name
  • this.run = function () {
  • console.log(this.name,“在跑步”)}
  • }
  • let p = new Person('zhangsan)
  • p.run();
    */

// ts 中定义类
class Person {
name: string;//
constructor(n:string) {// 构造函数,实例化类的时候触发的方法
this.name = n
}
run():void {
console.log(“isRunning”, this.name)
}
getName():string{
return this.name
}
setName(name: string):void {
this.name = name
}
}
let p1 = new Person(‘zhangsan’)
p1.run();
console.log(p1.getName());

p1.setName(‘lisi’)
// ts中实现继承 extends + super
class Person2 {
name: string;//
constructor(n:string) {// 构造函数,实例化类的时候触发的方法
this.name = n
}
run():void {
console.log(“isRunning”, this.name)
}
getName():string{
return this.name
}
setName(name: string):void {
this.name = name
}
}
class Web extends Person2 {
constructor(name:string) {
super(name)
}

}
let w = new Web(‘wangwu’);
w.run();
// ts 继承的探讨: 父类和子类中的方法一致。 子类中有和父类相同的方法时,优先会调用子类中的方法

// 类里面的修饰符: typescript里面定义属性的时候给我们提供了三种修饰符
/**

  • public 公有,在类里面、子类、类外部都可以访问
  • protected 保护类型, 在类里面和子类中可以访问,在类外部不可以访问
  • private 私有,在类里面可以访问,在类外部和子类都无法访问
  • 属性如果不加修饰符,默认就是 公有public
    */

class Person3 {
public name: string//公有属性
protected age:number // 只能类里面和子类访问
private money: number //私有属性
constructor(n:string) {// 构造函数,实例化类的时候触发的方法
this.name = n
}
run():void {
console.log(“isRunning”, this.name)
}
getName():string{
return this.name
}
setName(name: string):void {
this.name = name
}
}
class Web2 extends Person3 {
constructor(name:string) {
super(name)
}

}
let web = new Web2(‘wangwu’);
web.run();
console.log(web.name);
// console.log(web.age)
// console.log(web.money)

// 静态属性 静态方法
// es5中的静态
function Person4(){
this.run1 = function() {} //实例方法,实例化后调用
}
Person4.run2 = function(){}//静态方法 里面没法直接调用类的属性,想要调用则需要把属性变为static的静态方法

// 多态: 父类定义一个方法不去实现,让继承它的子类去实现,每一个子类有不同的表现
// 多态也是继承的一种表现,多态属于继承
class Animal {
name:string
constructor(name:string) {
this.name = name
}
eat(){// 具体吃什么, 不知道,具体吃什么?继承它的子类去实现,不同的子类表现不一样
console.log(“eat 的方法”)
}
}

class Dog extends Animal {
constructor(name:string){
super(name)
}
eat() {
return this.name +‘吃肉’
}
}

class Cat extends Animal {
constructor(name:string){
super(name)
}
eat() {
return this.name +‘吃老鼠’
}
}

let dog = new Dog(“小花花”)

// ts 中的抽象类:他是提供其他类继承的基类,不能直接实例化
// 用 abstract 关键字定义抽象类和抽象方法,抽象类中的抽象方法不包括具体实现并且必须在派生类中实现。
// abstract 抽象方法只能放在抽象类里面
// 抽象类和抽象方法用来定义标准 Animal 这个类要求它的子类必须包含eat 方法
// 标准:

abstract class Animal2 {
public name:string
constructor(name:string) {
this.name = name
}
abstract eat():any
}

// let j = new Animal2()//错误写法,因为不能直接实例化
class Dog2 extends Animal2 {
constructor(name:any) {
super(name)
}
// 抽象类的子类必须实现抽象类里面的抽象方法
eat() {
console.log(this.name + ‘吃粮食’)
}
}

let d = new Dog2(“xiaohei”)
d.eat();

Typescript 中的接口

/**

  • 接口的作用: 在面向对象的编程中, 接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。
  • 接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,
  • 提供这些方法的类就可以满足实际需要,typescript 中的接口类似于 java ,同时还增加了更灵活的接口类型,包括属性\函数\可索引和类等.
  • 相当于定义标准
    */

/***

  • 属性接口 -------- 对json 的约束
    */

// ts 中定义方法
// function printLabel(label:string):void{
// console.log(‘printLabel’)
// }
// printLabel(‘12330’);

// ts 中定义方法传入参数
// function printLabel(label:string):void{
// console.log(‘printLabel’)
// }
// printLabel(‘12330’);
// ts中自定义方法传入参数对 json 进行约束

function printLabel(labelInfo:{label:string}):void{
console.log(‘printLabel’)
}
let labelInfo = {}
// printLabel(‘labelInfo’);// 错误写法
// printLabel({name:“zhangsan”})//错误写法
// printLabel({label: ‘111’})//正确写法

// 可批量方法传入参数进行约束
// 接口:行为和动作的规范,对批量方法进行约束
// interface FullName {
// firstName: string;
// secondName: string
// }
// function printName(name: FullName) {
// // 必须传入对象 firstName secondName
// console.log(name.firstName+‘----’+name.secondName)// 如果打印 age 的属性就会报错
// }

// // printName(‘123’) // 错误写法
// let obj = {
// age: 20,
// firstName:‘zhang’,
// secondName:‘san’
// }// 传入的参数必须包含 firstName sencondName
// printName(obj)

/**

  • 接口: 可选属性
    */
    interface FullName {
    firstName: string;
    secondName: string;
    age?: Number; // 可选属性,可以不进行传参
    }
    function getName(name: FullName) {
    console.log(name)
    }
    // 参数的顺序可以不一样
    getName({
    firstName: ‘string’,
    secondName: ‘string11’
    })

interface RequestConfig {
type: string;
url: string;
data?: string;
dataTpe: string
}
// 原生封装 接口
function ajax(config: RequestConfig) {
let xhr = new XMLHttpRequest();
xhr.open(config.type,config.url,true);
xhr.send(config.data);
xhr.onreadystatechange = function (){
if(xhr.readyState == 4 && xhr.status == 200) {
console.log(“成功”);
if(config.dataTpe == ‘json’) {
JSON.parse(xhr.responseText)
} else {
console.log(xhr.responseText);
}
}
}
}
ajax({
type: ‘post’,
url: ‘http://www.baidu.com’,
dataTpe: ‘json’
})

// 函数类型接口: 对方法传入的参数 以及返回值进行约束 批量约束

// 加密的函数类型接口
interface encrypt{
(key: string, value:string): string;
}
let md5:encrypt = function(key:string,value:string):string {
// 模拟操作
return key+value;

}
console.log(md5(‘name:’, “zhangsan”));
let sha1:encrypt = function(key:string,value:string):string {
// 模拟操作
return key+‘–>’+value;

}
console.log(sha1(‘name’, “lisi”));

// 可索引接口, 数组、对象的约束 不常用

// ts 中定义数组的方式
/**

  • var arr:number[] =[1,2]
  • var arr1:Array = [‘123’,‘333’];
    */

// 可索引接口,对数组的约束
interface UserArr {
[index: number]: string
}

// let arr:UserArr = [124,‘bbb’]// 错误写法

// 可索引接口 对对象的约束
interface UserObj {
[index: string]:string
}
let arr4:UserObj = {
name: “zs”
}

// 类类型接口,对类的约束 和抽象类有点相似.
interface Animal3 {
name: string;
eat(strL:string):void;
}
class Dog3 implements Animal3 {
name:string;
constructor(name:string) {
this.name = name;
}
eat() {
console.log(this.name +“吃肉”)
}
}
let d3 = new Dog3(“大黄”);
d3.eat();

class Cat3 implements Animal3 {
name:string;
constructor(name:string) {
this.name = name;
}
eat(food:string) {
console.log(this.name +food)
}
}
let cat3 = new Cat3(“小花”)
cat3.eat(“老鼠”)

// 接口扩展: 接口可以继承接口
interface Animal4 {
eat():void;
}

interface Person4 extends Animal4 {
work():void
}
class Web4 implements Person4 {
name:string;
constructor(name:string) {
this.name = name;
}
eat(){
console.log(this.name +‘喜欢吃馒头’)
}
work() {
console.log(this.name+“正在工作”)
}
}

let w4 = new Web4(“小磊”)
w4.eat();

Typescript 中的泛型

/**

  • 泛型: 在软件工程中,我们不仅要创建一致的定义良好的 API ,同时也要考虑可重用性。组件不仅能够支持当前的数据类型,
  • 同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。
  • 在像c# 和 Java 这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。这样用户就可以以自己的数据类型来使用组件。
  • 通俗理解:泛型就是解决 类 接口 方法的复用性,以及对不特定数据类型的支持。
    */

// 同时返回 string 类型 和 number 类型
// function getData() {}

// any 可以返回任意类型,但是这么使用以后就类似于放弃了类型检查
// 泛型:可以支持不特定的数据类型 要求:传入的参数和返回的参数一致

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

getData(123)
getData(‘hahah’)// 方法名<类型>(值):返回值类型

// 泛型类: 比如有个最小堆算法,需要同时支持返回数字和字符串两种类型。通过类的泛型来实现
/**

  • class MinClass {
    public list:number[] = [];
    add(num: number) {
    this.list.push(num)
    }
    min():number {
    let minNum = this.list[0];
    for(let i = 0;i< this.list.length;i++) {
    if(minNum>this.list[i]) {
    minNum = this.list[i];
    }
    }
    return minNum;
    }
    }

    let min = new MinClass();
    min.add(102);
    min.add(912);
    min.add(182);
    min.add(120);
    min.add(1.2);
    min.add(123);
    console.log(min.min());

*/

// 类型的泛型

class MinClass {
public list:T[] = [];
add(num:T):void {
this.list.push(num)
}
min():T {
let minNum = this.list[0];
for(let i = 0;i< this.list.length;i++) {
if(minNum>this.list[i]) {
minNum = this.list[i];
}
}
return minNum;
}
}

let min = new MinClass();// 实例化类,并且指定了类的 T 代表的类型是 number
min.add(102);
min.add(912);
min.add(182);
min.add(120);
min.add(1.2);
min.add(123);
console.log(min.min());

let min2 = new MinClass();// 实例化类,并且指定了类的 T 代表的类型是 String
min2.add(‘5’);
min2.add(‘b’);
min2.add(‘c’);
min2.add(‘a’);
console.log(min2.min());

// 注: any 的性能低于泛型

// 函数类型接口
interface configFn {
(value1:string,value2:string):string;
}
let setData:configFn = function(value1:string,value2:string):string {
return value1 + value2
}
setData(“name”,‘zhangYiShan’)

// 泛型接口

interface configFn2 {
(value:T):T;
}
let setData2:configFn2 = function(value:T):T {
return value
}
setData2(“name”)

// Typescript 中的泛型

/**

  • 定义一个 User 的类,这个类的作用就是映射数据库字段
  • 然后定义一个 MysqlDb 的类,这个类用于操作数据库
  • 然后把User类作为参数传入到 MysqlDb 中
    */

class User {
username:string | undefined;
password:string | undefined
}

class MysqlDb {
add(user:User):boolean {
console.log(user);
return true;
}
}

let u = new User();

u.username = ‘zhangshan’;
u.password = ‘123456’

let db = new MysqlDb();
db.add(u);

class MysqlDb2 {
add(info:T):boolean {
console.log(info)
return true
}
}

class ArticleCate {
title:string | undefined;
desc:string | undefined;
author:string | undefined
}

/**

  • 功能: 定义一个操作数据库的库 支持 Mysql MongoDB
  • 要求1: Mysql MongoDB 功能一样, 都有 add update delete get 方法
  • 注意: 约束统一的规范,以及代码重用
  • 解决方案: 需要约束规范所以要定义接口,需要代码重用所以用到泛型
  • 1、接口:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范
  • 2、泛型:通俗理解 就是解决 类、接口 方法的复用性
    */

interface DBI {
add(info:T):boolean;
update(info:T, id: number):boolean;
delete(id:number):boolean;
get(id:number):any []
}
// 定义一个操作mysql 数据库的类 注意:要实现泛型接口 这个类也应该是一个泛型类
class MysqlDb3 implements DBI {
add(info: T):boolean {
throw new Error(“Method not implemented”);
}
update(info:T, id: number):boolean {
throw new Error(“Method not implemented”);
}
delete(id:number):boolean {
throw new Error(“Method not implemented”);
}
get(id:number):any[] {
throw new Error(“Method not implemented”);
}
}
// 定义一个操作 mysql 数据库的类
class MysqlDb4 implements DBI {
add(info: T):boolean {
throw new Error(“Method not implemented”);
}
update(info:T, id: number):boolean {
throw new Error(“Method not implemented”);
}
delete(id:number):boolean {
throw new Error(“Method not implemented”);
}
get(id:number):any[] {
throw new Error(“Method not implemented”);
}
}
// 操作用户表 定义一个 User 类 和数据库表做映射
class User3 {
username:string | undefined;
password:string | undefined
}

let u2 = new User3();
u2.username = ‘lisi’
u2.password = ‘999’
let oMysql = new MysqlDb3();
oMysql.add(u2)

/**

  • 命名空间:
  • 在代码量比较大的情况下,为了避免各种变量命名相冲突,可将相似功能的函数、类、接口等放置到命名空间内
  • 同Java的包、.Net的命名空间一样,Typescript 的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象,命名空间内的对象通过export
  • 命名空间和模块的区别:
  • 命名空间:内部模块,主要用于组织代码,避免命名冲突
  • 模 块:ts 的外部模块的简称,侧重代码的复用,一个模块里可能会有多个命名空间
    */

namespace A {
interface Animal3 {
name: string;
eat(strL:string):void;
}
export class Dog3 implements Animal3 {
name:string;
constructor(name:string) {
this.name = name;
}
eat() {
console.log(this.name +“吃肉”)
}
}
export class Cat implements Animal3 {
name:string;
constructor(name:string) {
this.name = name;
}
eat() {
console.log(this.name +“吃猫粮”)
}
}
}
let d4 = new A.Dog3(“狗狗”)
d4.eat();
namespace B {
interface Animal3 {
name: string;
eat(strL:string):void;
}
export class Dog3 implements Animal3 {
name:string;
constructor(name:string) {
this.name = name;
}
eat() {
console.log(this.name +“吃肉”)
}
}
export class Cat implements Animal3 {
name:string;
constructor(name:string) {
this.name = name;
}
eat() {
console.log(this.name +“吃猫粮”)
}
}
}
let cat4 = new A.Cat(“小花”)
cat4.eat();

Typescript 中的装饰器

/**

  • 装饰器: 装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为
  • 通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能
  • 常见的装饰器的写法: 类装饰器、属性装饰器、方法装饰器、参数装饰器
  • 装饰器的写法: 普通装饰器(无法传参)、装饰器工厂(可 传参)
  • 装饰器是过去几年中 js 最大的成就之一,已经是ES7的标准特性之一
    */

/ 1、类装饰器: 类装饰器在类声明之前被声明(紧接着类声明)。类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。传入一个参数

/**

  • 普通装饰器(无法传参)
  • //装饰器 — 在不修改类的前提下扩展类的属性和方法
    function logClass(parms:any) {
    console.log(parms)// 就是当前类

parms.prototype.apiUrl = ‘动态扩展的属性’
parms.prototype.run = function() {
console.log(“动态扩展 run 方法”)
}
}

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

}
}
*/

/**

  • 装饰器工厂
    */
    function logClass(parms:any) {
    console.log(parms)
    return function(target: any) {
    console.log(parms,‘---->’, target)
    }
    }

@logClass(‘hello’)
class HttpClient {
constructor() {}
getData(){

}
}
/**

  • 类装饰器
  • 下面是一个重载构造函数的例子
  • 类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数
  • 如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。
    */

/**

  • 属性装饰器
  • 属性装饰器表达式会在运行时当作函数被调用,传入下面2个参数:
  • 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  • 2、成员的名字
    */

/**

  • 方法装饰器
  • 它会被应用到方法的属性描述符上,可以用来监视、修改或者替换方法定义
  • 方法装饰会在运行时传入下面3个参数:
  • 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  • 2、成员的名字
  • 3、成员的属性描述符
    */

function get(params:any) {
return function(taget:any,methodName:any,desc:any) {
console.log(taget, methodName, desc)
taget.apiUrl = ‘xxx’;
taget.run = function() {
console.log(“run”)
}
}
}

class HttpClient2 {
public url:any|undefined;
constructor() {}
@get(“http://xxx.com”)
getData(){
console.log(this.url)
}
}
let http = new HttpClient2();

/**

  • 方法参数装饰器
  • 参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入以下3个参数:
  • 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  • 2、参数的名字
  • 3、参数在函数参数列表中的索引
  • */

function logParams(params:any) {

}
class HttpClient3 {

}

你可能感兴趣的:(typescript,typescript,学习,笔记)