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')
}
}
接口
用于规范的定义
- 对象的约束 属性接口
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; // 加? 可传可不传
}
- 函数类型接口:对方法传入的参数 以及返回值进行约束
interface encrypt {
(key:string, value:string): string;
}
let md5:encrypt = function(key:string, value:string): string {
return key+value
}
- 可索引接口: 数组,对象的约束 (不常用)
<!-- 对数组的约束 -->
interface UserArr {
[index:number]: string;
}
let arr: UserArr = ['aaa','bbb'];
console.log(arr[0])
<!-- 对对象的约束 -->
interface UserObject{
[index:string]:string
}
var obj:UserObject = {name: 'kaka'}
- 类 类型接口 对类的约束
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')
- 接口的扩展
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
装饰器
通俗的讲装饰器就是一个方法,可以注入到类,方法,属性或参数上来拓展类,属性,方法和参数的功能。
类装饰器
- 类装饰器--不传参
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()
- 类装饰器--接受传参 (装饰器工厂)
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();
- 重载构造函数
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()
属性装饰器
属性装饰器表达式会在运行时当做函数被调用,传入下列两个参数
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 成员的名字
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个参数
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 成员的名字
- 成员的属性描述符
方法参数装饰器
会在运行时当做函数被调用,可以使用参数装饰器为类的原型增加一些元素数据
传入下列三个参数
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 成员的名字
- 参数在函数参数列表中的索引