数据类型
定义类型时,必须(最好)指定变量类型
-
布尔类型 boolean
-
数字类型 number
-
字符串类型 string
-
数组类型 array
let arr1: Array<string> = ["a", "b", "c"]; let arr2: string[] = ["a", "b", "c"]; let arr3: any[] = ["a", "b", 4];
-
元组类型 tuple
-
也是数组的一种
// 必须为每一个数组元素单独指定类型(顺序不能调换;必须与元素数量一致) let arr3: [number, string] = [123, "a"];
-
枚举类型 enum
enum Flag { success = 0, failed = 1 } // 打印得到对应的赋值;如果没有赋值的话就是对应下标 const fl: Flag = Flag.success; const fa: Flag = Flag.failed; // fixme 如果自定义中间某个元素的 value = val ,再打印的话,该元素前后的元素 value 是什么??? // 后面的 value = val + 1; // 前面的没有指定 value 的仍然按照默认的赋值
-
任意类型 any
// 不晓得什么类型的就可以这么用 let oBox: any = document.getElementById("box"); oBox.style.color = 'red';
-
null 和 undefined
-
定义的变量未赋值时就是 undefined
// 一个元素可能是多种类型 let num2: number | undefined; console.log(num2); // null 空类型;一个变量为空类型时就只能赋值 null let nul:null; nul = null;
- void 类型
-
表示没有任何类型
-
一般用于定义方法的时候表示没有返回值
// 方法不能返回多种类型 function run(): void { console.log("void一般表示方法没有返回类型") }
- never 类型
-
是其他类型(包括 null 和 undefined)的子类型,代表从不会出现的值
-
意味着声明 never 的变量只能被 never 类型所赋值
let nev: never; // nev = 3; nev = (() => { throw new Error("错误"); })(); // 最后的这个括号什么意思???
函数定义
-
函数声明法
function func(): number { return 1; }
-
匿名函数
const func0 = function (): number { return 123; }; func0();
-
方法和可选参数
// 使用问号 ? 表示参数可选 // 可选参数必须是最后一个 function func2(name: string, age?: number): void { if (age) { console.log(`${name}`); } else { console.log(`${name} --- ${age}`); } } func2("yangcx");
-
方法默认参数
// 通过等号赋予了默认值,就不能使用 ? 表示参数可选 // 其实通过 = 也表示了参数可选,不过有了默认值 function func3(name: string, age: number = 20): void { console.log(`${name} --- ${age}`); } func3("张三",30);
-
剩余参数(三点运算符接收)
// 调用的时候优先满足前面明确的参数赋值,剩下的全部赋给...arg function func4(a: number, ...result: number[]): number { let sum = 0; result.forEach(((value) => { sum += value; })); return sum; }
-
函数重载(类似于Java的实现)
// 多种方法定义,不能拥有具体的方法实现 // 存在一个同名的方法负责具体实现(所有参数及返回都必须定义为 any ) function getUserInfo(name: string): string; function getUserInfo(age: number, address?: string): string; function getUserInfo(str: any): any { if (typeof str === 'string') { return "My name is " + str; } else if (typeof str === 'number') { return "My age is " + str; } } console.log(getUserInfo("李晨")); console.log(getUserInfo(42));
-
箭头函数(里面的 this 指向上下文)
// 这只是一个非常简单的示范,具体还需要去看 ES6 语法 setInterval(() => { alert("箭头函数"); }, 1000);
类
-
ES5类定义
function Person() { // 属性 this.name = "张三"; this.age = 20; // 实例方法 this.run = function () { alert(this.name + " 在运动..."); } } let person = new Person(); person.run(); // 原型链上面的属性会被多个实例共享;构造函数的不会 Person.prototype.sex = "男"; Person.prototype.work = function () { alert("张三在工作"); }; console.log(person.sex);
-
ES5类中的静态方法
Person.getInfo = function () { console.log("静态方法"); }; Person.getInfo();
-
ES5中的继承(原型链+对象冒充的组合继承模式)
//对象冒充实现 function Web() { Person.call(this); } let web = new Web(); //对象冒充可以继承构造函数里面的属性和方法 web.run(); //但是无法继承原型链上面的属性和方法 // web.work(); //原型链实现 Web.prototype = new Person(); let w = new Web(); // 可以同时继承构造函数和原型链的属性和方法 // 如果父类为有参构造,子类实例化时无法给父类传参 w.run(); w.work(); // 综合实现写法一 function Man(name,age){ Person.call(this,name,age);//对象冒充 } Woman.prototype = new Person();//原型链 // 综合实现写法二 function Woman(name,age){ Person.call(this,name,age); } Woman.prototype = Person.prototype;
-
TypeScript中定义类(new 对象的时候都无法使用对应类型进行接收)
class Person { name: string; age: number; //构造函数 constructor(name: string, age: number) { this.name = name; this.age = age; }; //方法定义 run(): void { alert(this.name); } getName(): string { return this.name; } setName(name: string): void { this.name = name; } } let person = new Person("张三", 25); person.run();
-
TypeScript实现类继承(new 对象的时候都无法使用对应类型进行接收)
// 通过 extends 关键字实现继承 class Man extends Person { // 必须 super 对应的构造函数 constructor(name: string, age: number) { super(name, age); } } const man = new Man("王五", 25); man.run(); // 与 Java 继承类似,子类可以调用(override)父类方法或扩展自己的方法
-
TypeScript中的修饰符(与 Java 类似;属性不加修饰符,默认就是 public 的)
- public 共有的;当前类及子类、类外面都可以访问
- protected 保护类型;当前类、子类可以访问,类外面无法访问
- private 私有类型;仅当前类可以访问
class Person { // protected private public name: string; constructor(name: string) { this.name = name; } consoleName(): void { console.log(this.name); } } let p = new Person("张三"); // 跟 Java 类似,直接访问对应属性失败,通过对应的方法可以访问 console.log(p.name);
-
TypeScript 静态方法 静态属性
class Person { // static 修饰即可 static sex: string = "男"; static staticMethod(): void { alert('静态方法就没得this获取属性能力了,除非获取静态属性:' + Person.sex); } } // 直接类名调用就行 Person.staticMethod();
-
TypeScript 的多态(属于继承;父类定义方法,可提供默认实现;由子类提供具体实现;各子类可以有不同的实现)
-
TypeScript 抽象方法 抽象类
-
abstract 关键字
-
抽象类提供其他类继承的基类,不能直接被实例化
-
抽象方法不包含具体实现并且必须在派生类中实现
-
存在抽象方法的类必须是抽象类(跟Java类似)
abstract class Animal { //提供方法定义即可 abstract eat(): any; } class Dog extends Animal { name: string; constructor(name: string) { super(); this.name = name; } // 必须实现抽象方法 eat(): any { console.log("阿福"); } // 可以拥有自己的方法 run(): void { console.log(`${this.name} is running...`) } } let dog = new Dog("dog"); dog.eat(); dog.run();
-
-
TypeScript 接口
- 属性类接口 对json的约束
- 函数类型接口
- 可索引接口
- 类类型接口
- 接口扩展
// 属性类接口 // 不使用类型约束 function printLabel(labelInfo: { label: string }): void { console.log(labelInfo.label); } // 相当于使用匿名类定义入参 printLabel({label: "not a interface"}); // 属性类接口 interface Label { name: string; // 参数可选 width?: number; height?: number // 设置候选值 dataType?: 'json' | 'jsonp' } function drawLabel(label: Label): void { console.log(label.height + " <===> " + label.width); } // 直接将属性定义放在调用方法上不能添加任何自定义属性 drawLabel({name: "label"}); // 这么写虽然可以添加自定义属性,但是破坏了TS提供的类型校验 let otherLaber = { name:"label", width:10, brightness:"dark" }; drawLabel(otherLaber); // (推荐)还是把对应的类型限制加上最好 let otherLaber2:Label = { name:"label", width:10 }; drawLabel(otherLaber);
// 函数类型接口 interface Encrypt { (key: string, value: string): string; } let md5: Encrypt = function (key: string, value): string { // 模拟操作 return key + value; }; md5("yangcx", "20200330");
// 可索引接口:数组、对象的约束(没什么卵用) // 数组 // interface UserArray { // // 定义的格式 索引:值 // [index: number]: string; // } // let arr: UserArray = ['aaa', 'bbb']; // console.log(arr[0]); // // 对象 // interface UserObj { // [index: string]: string; // } // let user: UserObj = {name: "yangcx"}; // 类类型接口:对类型的约束(与抽象类类似) interface Animal { // 同时包含属性与方法定义 name: string; eat(food: string): void; } // 采用实现 implements class Dog implements Animal { name: string; // 需要进行构造 constructor(name: string) { this.name = name; } // 实现方法 eat(food: string): void { console.log("A " + this.name + " is eating " + food); } // 可以拥有自定义方法 wc() { console.log(this.name + " is wcing..."); } } let dog = new Dog("dog"); dog.eat("bone"); dog.wc();
// 接口扩展:接口可以继承接口 // 语法上跟 Java 非常类似 interface Animal { eat(food?: string): void; } interface Person extends Animal { work(): void; } class Programmer { name: string; constructor(name: string) { this.name = name; } coding(language: string) { console.log(this.name + " is coding " + language); } } class Web extends Programmer implements Person { eat(food?: string): void { console.log(this.name + " eat " + food); } work(): void { console.log(this.name + " is working..."); } } let web = new Web("小明"); web.work(); web.coding("TypeScript");
-
TypeScript 泛型
// 泛型函数 function getData<T>(value: T): any { return value; } console.log(getData("yangcx")); // 泛型类 class MinClass<T> { public list: T[] = []; add(value: T): void { this.list.push(value); } 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 minCls = new MinClass<number>(); // 泛型接口定义一 interface ConfigFn { <T>(value: T): T; } let getData: ConfigFn = function <T>(value: T): T { return value; }; getData<string>("yangcx"); // 泛型接口定义二 // (也可以像 函数类型接口 这么用,但是可能每次都要写完整的函数定义) interface ConfigFn<T> { (value: T): T; } function getData<T>(value: T) { return value; } let myGetData: ConfigFn<number> = getData; console.log(myGetData(1)); // 将类作为参数类型校验(就是 泛型类) class DbUtil<T> { add(t: T): boolean { console.log("add: " + t); return true; } update(t: T): boolean { console.log("update: " + t); return true; } }
-
TypeScript模块
- 内部模块(命名空间;主要用于组织代码,避免命名冲突)
// 命名空间也支持 export export namespace A { interface Animal { eat(food: string): void; } export class Dog implements Animal { eat(food: string): void { console.log(food); } } } namespace B { interface Animal { eat(food: string): void; } export class Dog implements Animal { eat(food: string): void { console.log(food); } } } let aD = new A.Dog(); aD.eat("bone");
- 外部模块(侧重于代码复用,一个模块可能会有多个命名空间)
let dbUrl = "jdbc:mysql://127.0.0.1:3306"; function getData(): any[] { console.log("get data from db"); return [ { title: "11111" }, { title: "11111" } ]; } // 可以单独 export 每一个方法或变量;也可以使用 export 进行统一处理 export {dbUrl, getData} // 引入 // as 起别名 import {getData as get,dbUrl} from './modules/db'; // 默认 export // 当一个组件只需要 export 出一个方法或变量时 // 一个组件中只能存在一个 export default export default getData; import getData from './modules/db';
-
装饰器(是一种特殊的类型声明,能够被附加到类声明、方法、属性或参数上,可以修改类的行为)
// 1、类装饰器:普通装饰器(无法传参) function logClass(params: any) { // params 参数就是对应的类(HttpClient) console.log(params); // 可以进行扩展 params.prototype.apiUrl = "xxxxx"; params.prototype.run = function () { console.log("run..."); } } @logClass class HttpClient { constructor() {} getData(): any[] { return []; } } // 可以获取到扩展的属性 let httpClient: any = new HttpClient(); console.log(httpClient.apiUrl);
// 2、类装饰器:装饰器工厂(可传参) // 2.1 普通扩展 function logClass(params: string) { return function (target: any) { // target 是被扩展的类(HttpClient) console.log(target); // params 是传递过来的参数("hello") console.log(params); // 可以进行扩展 target.prototype.apiUrl = "https://www.baidu.com" } } @logClass("hello") class HttpClient { constructor() {} getData(): any[] { return []; } } let httpClient: any = new HttpClient(); console.log(httpClient.apiUrl); // 2.2 重载对应的构造函数及方法等 function logClass(target: any) { console.log(target); // 重载对应的构造函数及方法等 return class extends target { apiUrl: any = "修改后的apiUrl"; getData(): void { this.apiUrl = this.apiUrl + "===="; console.log(this.apiUrl); } } } @logClass class HttpClient { apiUrl: string | undefined; constructor() { this.apiUrl = "构造函数初始化的apiURL"; } getData(): void { console.log(this.apiUrl); } } let httpClient = new HttpClient(); httpClient.getData();
// 3、属性装饰器 function classDecorator(params: any) { console.log("这是类装饰器的传参:" + params); return function (target: any) { console.log("target 是被扩展的类:" + target); } } function fieldDecorator(params: any) { console.log("这是属性装饰器的传参:" + params); return function (target: any, attr: any) { console.log("这是被装饰的类:" + target); console.log("这是被装饰的属性:" + attr); // 改一下属性值 TODO 改不掉在构造函数中给的值 target[attr] = params; } } @classDecorator("class") class HttpClient { @fieldDecorator("field") url: string | undefined; constructor() { // this.url = "构造函数初始化的url"; } getData(): void { console.log(this.url); } } let httpClient = new HttpClient(); httpClient.getData();
// 4、方法装饰器 // 被应用到方法的属性描述符上,用来监视、修改或替换方法定义 // 接收三个入参: // 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象 // 方法的名称 // 方法的属性描述符 // 扩展属性及方法 function methodDecorator(params: any) { console.log(params); return function (target: any, methodName: string, methodDesc: any) { console.log(target); console.log(methodName); console.log(methodDesc); // 扩展属性及方法(相当于操作 prototype) target.apiUrl = "xxxx"; target.run = function () { console.log("run..."); } } } class HttpClient { url: string | undefined; constructor() {} @methodDecorator("method") getData() { console.log(this.url); } } let httpClient: any = new HttpClient(); console.log(httpClient.apiUrl); httpClient.run(); // 修改方法 function methodDecorator(params: any) { console.log(params); return function (target: any, methodName: string, methodDesc: any) { // 方法本尊 console.log(methodDesc.value); // 修改方法 let _method = methodDesc.value; methodDesc.value = function (...args: any[]) { args = args.map((value) => { return String(value); }); console.log(args); // 在当前方法中传入参数 args 并调用 _method _method.apply(this, args); } } } class HttpClient { @methodDecorator("method") getData(...args: any[]) { // 可以获取到装饰器修改后的参数 console.log("getData()===>" + args); console.log("getData()方法执行了"); } } let httpClient: any = new HttpClient(); httpClient.getData(123, 'xyz');
// 方法参数装饰器 // 用的很少,可以通过类装饰器实现
装饰器的执行顺序:
- 属性装饰器 > 方法装饰器 > 方法参数装饰器 > 类装饰器
- 如果存在多个同样的装饰器,会先执行后面的