前段时间发表了node的学习
现在丸子终于要对ts进行总结跟回顾了
目录
- 函数
- 类型约束
- 函数重载
- this问题
- 类
- .静态成员
- 继承
- 抽象类
- 接口基础
- 接口可选结构
- 接口检测约束
- 接口索引签名
- 接口函数类型接口
- 类接口
- 案例
/**
* 函数
* 函数声明
* 函数表达式
*
* 类型约束
* 函数参数
* 函数返回值
*
* 如果函数没有返回值,使用 void,不是undefined
* // function fn1(x: number, y: number): number {
// return x + y;
// }
// fn1(1,2);
// fn1('a', 'b');
// 函数表达式
// let fn2 = function(x: number, y: number): number {
// return x + y;
// }
// let a: number = 1;
// let fn2: (x: number, y: number) => number = function(x: number, y: number): number {
// return x + y;
// }
// 根据类型推断可以简写
// let fn2: (x: number, y: number) => number = function(x, y) {
// return x + y;
// }
// fn2('a', 'b');
// fn2('a', 'b');
// fn2(1, 2);
// 可选参数
// function fn3(x: number, y?: number): void {}
// fn3(1);
// 参数默认值
// function fn3(x: number, y = 1): void {
// console.log(y);
// }
// fn3(0);
// 剩余参数
// function fn4(...args: any[]) {
// console.log(args);
// }
*/
2.函数重载
// 如果是在js中
// function fn(x, y) {
// return x + y;
// }
// fn(1, 2);
// fn('a', 'b');
// 函数重载
// function fn(x: number, y: number): number;
// function fn(x: string, y: string): string;
// function fn(x: any, y: any): any {
// return x + y;
// }
// fn(1, 2);
// fn('a', 'b');
// fn(1, 'a');
ts里面的this
/**
* ts中默认情况下函数中的this默认指向 : any
*/
let obj = {
a: 10,
fn() {
// 因为默认情况下,this是any类型,any类型ts不能提示有任何属性方法
// let document:any;
// any的值,ts不能提示或者进行类型属性检测
// console.log(this.b);
// 使用noImplicitThis选项可以取消默认this的any来这个设置
// this.a
}
}
// obj.fn();
// ts会自动推导事件函数中的this
// document.onclick = function() {
// this
// }
let obj1 = {
a: 1,
fn(this: Element|Document) { // 在ts中函数的第一个this参数是用来设置this类型约束的
// 这个this是一个假参数,运行过程中是不存在,是给ts检测使用的
// console.log(this);
// 希望ts是按照事件函数中的this去做检测
this; //检测检测检测
// this
}
};
document.onclick = obj1.fn;
document.body.onclick = obj1.fn;
// function fn10(x: number) {
// }
// fn10( document.querySelector('input').value );
ts中的类
// class Person {
// /**
// * ts中的类,成员属性必须要声明后使用
// * ts中类的成员属性不是在构造函数中声明的,是在class内,方法外
// *
// * public
// * 公开的,所有的地方都能访问,属性和方法默认是public
// * protected
// * 受保护的,在类的内部和他的子类中才能访问
// * private
// * 私有的,只能在该对象(类)的内部才可以访问
// */
// public username: string = '';
// // private username: string = '';
// // protected username: string = '';
// // readonly username: string = '';
// constructor(name: string) {
// this.username = name;
// }
// }
// class Student extends Person {
// say() {
// this.username
// }
// }
// let p1: Person = new Person('Kimoo');
// p1.username = 'zmouse';
class Person {
username: string = 'Kimoo';
// private age: number = 10;
private _age: number = 10;
// getAge(): number {
// return this.age;
// }
// setAge(age: number): void {
// if (age > 0 && age < 150) {
// this.age = age;
// }
// }
// 存取器,这个a并不会作为方法,而是属性去访问
get age(): number {
return this._age;
}
set age(age: number) {
if (age > 0 && age < 150) {
this._age = age;
}
}
}
let p1: Person = new Person();
/**
* 允许在外部获取和修改age的值,但是不希望该修改成非法的,比如1000岁
*/
// p1.age = 1100;
// console.log(p1);
// p1.setAge(20);
// p1.setAge(200);
// console.log(p1.getAge());
// console.log( p1.a );
/**
* 单例
*/
// class Mysql {
// host: string;
// port: number;
// username: string;
// password: string;
// dbname: string;
// constructor(host = '127.0.0.1', port = 3306, username='root', password='', dbname='') {
// this.host = host;
// this.port = port;
// this.username = username;
// this.password = password;
// this.dbname = dbname;
// }
// query() {}
// insert() {}
// update() {}
// }
/**
* 创建一个Mysql对象,通过这个对象来操作数据库
* 如果我们不加以限制的话,这个Mysql是可以new出来多个对象的
* 每一个Mysql都会占用资源(内存)
*/
// let db = new Mysql();
// db.query();
// db.insert();
// let db1 = new Mysql();
// db1.query();
// db1.insert();
/**
* 通过某种方法控制系统同时只有一个Mysql的对象在工作
* 通过口头去约定是不靠谱的
*/
class Mysql {
// 静态属性,不需要通过new出来的对象方面,直接是通过Mysql类来访问
public static instance;
host: string;
port: number;
username: string;
password: string;
dbname: string;
private constructor(host = '127.0.0.1', port = 3306, username='root', password='', dbname='') {
this.host = host;
this.port = port;
this.username = username;
this.password = password;
this.dbname = dbname;
}
public static getInstance() {
if (!Mysql.instance) {
Mysql.instance = new Mysql();
}
return Mysql.instance;
}
query() {}
insert() {}
update() {}
}
// let db = new Mysql();
// console.log(Mysql.instance);
let db = Mysql.getInstance();
db.query();
db.insert();
4.继承
class Person {
private _a = 1;
// 在构造函数的参数中如果直接使用public等修饰符,则等同于同时创建了该属性
constructor(public username: string, public age: number) {
this.username = username;
this.age = age;
}
}
class Student extends Person {
// 如果子类没有重写构造函数,则直接父类的
// 如果子类重写了构造函数
// 注意:需要手动调用父类构造函数
// super:关键字,表示父类
constructor(username: string, age: number, public type: string) {
super(username, age); //执行父类构造函数
this.type = type;
}
}
let s1 = new Student('Kimoo', 30, 'javascript');
5.抽象类
abstract class Person { //抽象类不能实例化的
username: string;
constructor(username: string) {
this.username = username;
}
say() {
console.log('哈哈哈哈哈');
}
// 虽然子类都会有这样的特性,学习,但是子类学习具体过程不一 样,所在在父类确定
// 不了study方法的具体实现,父类只能有抽象约定,接收什么参数,返回什么内容
// 如果一个类中有抽象的方法了,那么这个类也必须是抽象的
abstract study(): void //抽象方面是没有具体代码的
}
class Student extends Person {
study() {
console.log('学生有学生的学习方法 - 需要老师教授');
}
}
class Teacher extends Person {
study() {
console.log('自学');
}
}
// 如果一个类继承了抽象的父类,就必须实现所有抽象方面,否则这个子类还是必须得为抽象的
// abstract class P extends Person {
// }
// new Person();
interface
// /**
// * interface
// * 为我们提供一种方式来定义某种结构,ts按照这种结构来检测数据
// *
// * 写法
// * interface 接口名称 {
// * // ... 接口规则
// * }
// *
// * 接口中定义的规则只有抽象描述,不能有具体的值与实现的
// *
// * 对象抽象 => 类(对象的抽象描述)
// * 类抽象 => 抽象类(如果一个类中拥有一个没有具体实现的抽象方法,就是抽象类)
// * 抽象类 => 接口(如果一个抽象类的成员全部是抽象的,那么可以看做接口)
// */
// interface Options {
// width: number,
// height: number
// }
// function fn(opts: Options) {}
// // 类型检测只检测必须的属性是否存在,不会按照顺序进行,无序的
// fn({
// height: 200,
// width: 100
// });
可选结构
// /**
// * 如果规则中有些是可选的,那么通过 ? 标识
// */
// interface Options {
// width: number,
// height: number,
// color?: string
// }
// function fn(opts: Options) {}
// fn({
// height: 200,
// width: 100
// });
检测约束
// /**
// * 如果我们希望检测不必要这么复杂
// * - 如果我们希望某些时候,只要包含其中一些规则即可
// * - 通过可选 ? 来实现
// * - 通过 as 断言
// * - 通过变量转换
// */
// interface Options {
// width: number,
// height: number,
// color: string
// }
// function fn(opts: Options) {}
// // 告知ts检测,我传入的就是一个Options
// // fn({
// // height: 200,
// // width: 100
// // } as Options);
// // 先赋值给一个变量,也可以绕开 检测
// // let obj = {
// // height: 200,
// // width: 100,
// // color: 'red',
// // a: 1
// // }
// // fn( obj );
索引签名
// /**
// * 希望规则是:一组由数字进行key命名的对象
// * 我们可以使用索引签名
// * 为数据定义一组具有某种特性的key的数据
// * 索引key的类型只能是 number 和 string 两种
// */
// // interface Options {
// // // key 是number,value是any类型的数据
// // [attr: number]: any,
// // length: number
// // }
// // function fn(opt: Options) {}
// // fn({
// // 0: 100,
// // 1: 100,
// // 2: 2000,
// // length: 1
// // });
// interface Options {
// // 索引签名的key课是number,也可以是string
// [attr: string]: any,
// length: number
// }
// function fn(opt: Options) {}
// fn({
// a: 1,
// b: 2,
// length: 100
// });
函数类型接口
/**
* 这个接口描述的是一个包含有fn并且值的类型为函数的结构体,并不是描述函数结构
* 而是一个包含函数的对象结构
*/
// interface Options {
// fn: Function
// }
// let o: Options = {
// fn: function() {}
// }
// let fn: (x: number, y: number) => number = function(x: number, y: number): number {return x + y}
/**
* 定义一个事件函数,那么这个函数必须得有一定的规则了
* 我们不能随便的把一个函数赋值给事件
*/
// function fn(x: MouseEvent) {
// console.log(x.clientX);
// }
// document.onkeydown = fn;
// 我们也可以使用 interface 来约定定义函数的结构
// 定义的是函数接口
// interface IFn {
// (x: number, y: number): number
// }
// let fn: IFn = function(x: number, y: number): number {return x + y}
// 定义了一个接受一个MouseEvent类型参数的函数结构
// interface MouseEventCallBack {
// (e: MouseEvent): any
// }
// let fn: MouseEventCallBack = function(a: MouseEvent) {
// }
// document.onclick = fn;
// interface ResponseCallBack {
// (rs: Response): any
// }
// function todo(callback: ResponseCallBack) {
// callback(new Response);
// }
// todo(function(x: string) {
// });
// fetch('url').then( (a: Response) => {
// a.json();
// } );
// interface AjaxData {
// code: number;
// data: any
// }
// interface AjaxCallback {
// (rs: AjaxData): any
// }
// function ajax(callback: AjaxCallback) {
// callback({
// code: 1,
// data: []
// });
// }
// ajax( function(x: AjaxData) {
// x.code
// x.data
// x.message
// } );
类接口
/**
* 类接口
* 使用接口让某个类去符合某种契约
*
* 类可以通过 implements 关键字去实现某个接口
* - implements 某个接口的类必须实现这个接口中确定所有的内容
* - 一个类只能有一个父类,但是可以implements多个接口,多个接口使用逗号分隔
*/
/**
* 类接口
* 使用接口让某个类去符合某种契约
*
* 类可以通过 implements 关键字去实现某个接口
* - implements 某个接口的类必须实现这个接口中确定所有的内容
* - 一个类只能有一个父类,但是可以implements多个接口,多个接口使用逗号分隔
*/
interface ISuper {
fly(): void;
}
class Man {
constructor(public name: string) {
}
}
class SuperMan extends Man implements ISuper {
fly() {
console.log('起飞');
}
}
class Cat {
}
class SuperCat extends Cat implements ISuper {
fly() {
console.log('起飞');
}
}
let kimoo = new SuperMan('Kimoo');
案例
js的案例如下
function http(options) {
let options = Object.assign({
method: 'get',
url: '',
isAsync: true
}, options);
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open(options.method, options.url, options.isAsync);
xhr.onload = function() {
resolve( JSON.parse(xhr.responseText) );
}
xhr.onerror = function() {
reject({
code: xhr.response.code,
message: '出错了'
});
}
xhr.send();
})
}
http()
http({
methods: 'get',
url: '....',
isAsync: true
});
http({
methods: 'post',
url: '....',
isAsync: true
});
换成ts的写法
interface HttpOptions {
method: string,
url: string,
isAsync: true
}
interface HttpResponseData {
code: number,
data: any
}
function http(options: HttpOptions) {
let opt:HttpOptions = Object.assign({
method: 'get',
url: '',
isAsync: true
}, options);
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open(opt.method, opt.url, opt.isAsync);
xhr.onload = function() {
let data: HttpResponseData = JSON.parse(xhr.responseText);
resolve( data );
}
xhr.onerror = function() {
reject({
code: xhr.response.code,
message: '出错了'
});
}
xhr.send();
})
}
http({
method: 'get',
url: '....',
isAsync: true
}).then( (rs: HttpResponseData) => {
rs.code
} );
// @Controller
// class IndexController {
// index() {
// }
// @router('/')
// @method('get')
// main() {
// }
// }