TypeScript
1.编译
需要编译成 es5 语法,浏览器才能识别
tsc index.ts # 会生成同名的js文件
tsc --init # 生成tsconfig.json
# 修改tsconfig.json的outdir
# vscode里 终端→运行任务→typescript→监视tsconfig.json
2.数据类型
本节内容包括:boolean
、string
、number
、Array<T>
、[string,boolean]
、enum
、any
、undefined
、null
、never
、void
let a: string = "你好呀,typescript!"
let b: number = 5
let c: boolean = false
// 数组定义的两种方式
let e1: number[] = [1, 2, 3, 4]
let e2: Array<number> = [1, 2, 3, 4]
let f: [string, number, boolean] = ["str", 12, false] // 元组类型,指定对应元素的类型
enum Flag { success = 1, failed = 0 } // 若 a,b=4,c 则a:0,b:4,c:5 - 枚举值根据上一个的枚举值+1
let g: Flag = Flag.success // g === 1
let h: any = document.getElementById("h1")
h.style.color = 'red'
let d: number | undefined | null
console.log(d);
function print():void{
console.log("这个方法没有返回值");
}
print()
let n:never=(()=>{throw new Error("我也不知道它有啥用")})()
3.函数
本节内容包括:普通函数和匿名函数定义
、可选参数
、默认参数
、剩余参数
、函数重载
、箭头函数
function test1(): string {
return "返回string"
}
var test2 = function (): string {
return "匿名函数的用法"
}
function test3(name: string, age: number): string {
return `我叫${name},我今年${age}岁!`
}
var test4 = function (name: string, age: number): void {
console.log(`我叫${name},我今年${age}岁!`);
}
// 可选参数--可传可不传(注:必须在最后面,你应该懂得)
function test5(name: string, age?: number): void {
if (age) {
console.log(`我叫${name},今年${age}岁!`);
} else {
console.log(`我叫${name},年龄保密!`);
}
}
// 默认参数
function test6(name: string, age: number = 20): void {
console.log(`我叫${name},今年${age}岁!`);
}
// 剩余参数:数组参数,之前还有其他参数的话,按照顺序先赋值,剩余的赋值给数组
function test7(...arr: number[]): void {
console.log(arr);
}
// 重载函数:es5中,下面的方法会覆盖上面的相同函数名????????????????????????
function test8(a:number ):string;
function test8(a:string ):string;
function test8(arg: any): any {
if (typeof arg === 'string') {
return arg + '-return string'
} else {
return arg + '-return number'
}
}
console.log(test8("啊"));
console.log(test8(8));
// 箭头函数:
setInterval(() => {
console.log('箭头函数没变化!');
}, 1000)
4.类
本节内容包括es5的内容:类的定义
、静态方法
、对象冒充继承
、原型链继承
、组合继承
"use strict";
function Person(name, age) {
this.name = name
this.age = age
this.run = function () {
console.log(this.name + "在跑步...");
}
}
// 静态方法
Person.getInfo = function () {
console.log("我是静态方法...");
}
// 原型对象上添加共享的属性和方法,类似于“类“
Person.prototype.sex = "男"
Person.prototype.work = function () {
console.log(this.name + "在工作...");
}
// 调用
var p = new Person("罗志祥", 30)
p.run()
p.work()
Person.getInfo()
// 继承:对象冒充只会继承构造函数的内容,无法继承原型链上的
function Chinese() {
Person.call(this)
}
var yy = new Chinese()
yy.age = 22
yy.name = "yy"
yy.run()
yy.work() // Error:work is not a function
// 原型链继承:既可以继承原型链的方法也可继承后遭函数的方法-但无法给父类传参
function Chinese() {
}
Chinese.prototype = new Person()
var yy = new Chinese() // 传参无效
yy.run() // undefined 在跑步...
yy.work() // undefined 在工作...
// 组合继承: 对象冒充继承父类的属性、方法、构造对象格式;原型链继承父类原型的属性、方法
function Chinese(name,age) {
Person.call(this,name,age) // 对象冒充:可以继承构造函数的属性和方法,实例化子类
}
Chinese.prototype = Person.prototype // 再把Person的prototype的属性和方法继承下来
var yy = new Chinese('yy',20) // 传参有效
console.log(yy);
yy.run() // yy 在跑步...
yy.work() // yy 在运动...
本节部分包括的ts内容:类的定义
、继承
、类里面的修饰符
、静态属性和静态方法
、多态
、抽象类和抽象方法
写法如下:
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
getName(): string {
return this.name
}
setName(name: string): void {
this.name = name
}
run(): void {
console.log(this.name + '在跑步...');
}
}
var p = new Person('', 22)
p.setName('yy')
p.run()
console.log(p);
// 类的继承
class Chinese extends Person {
constructor(name: string) {
super(name)
}
run(): void {
console.log('子类:' + this.name + '在运动...');
}
work(): void {
console.log(this.name + '在工作...');
}
}
class Person {
// protected:在类和子类中可访问;private:在类中可访问
name: string // 默认是 public
private age: number=0
constructor(name: string) {
this.name = name
}
setAge(age: number): void {
this.age = age
}
getAge():number{
return this.age
}
run(): void {
console.log(this.name + '在运动...');
}
}
class Person {
// protected:在类和子类中可访问;private:在类中可访问
name: string // 默认是 public
private age: number = 0
static type: string = 'human'
constructor(name: string) {
this.name = name
}
setAge(age: number): void {
this.age = age
}
getAge(): number {
return this.age
}
run(): void {
console.log(this.name + '在运动...');
}
work(): void {
}
// 静态属性与静态方法
static show(): void {
console.log('我是静态方法...');
console.log('只可访问静态属性-' + Person.type);
}
}
// 多态:父类定义一个方法不去实现,子类各自实现自己的该方法
class Chinese extends Person {
constructor(name: string) {
super(name)
}
work(): void {
console.log('中国人在工作...');
}
}
class Japanese extends Person {
constructor(name: string) {
super(name)
}
work(): void {
console.log('日本人在工作...');
}
}
var yy = new Chinese('yy')
yy.work()
var xx = new Japanese('Akow')
xx.work()
// 抽象类和抽象方法:抽象方法只能放在抽象类中且不实现,子类必须实现
abstract class Animal {
abstract eat(): void
}
class Dog extends Animal {
name: string
constructor(name: string) {
super() // 必须调用这个
this.name = name
}
eat(): void {
console.log(this.name + '在吃东西...');
}
}
var dog = new Dog('哈士奇')
dog.eat()
5.接口
定义:接口是一种规范的定义,定义了行为和动作的规范,起到一种限制和规范的作用
本部分内容包括:接口对参数限制
、接口参数可选
、类类型接口
、函数类型接口
、继承接口
、可索引接口(不常用)
// 对批量方法进行约束
// 对参数限制
interface FullName {
firstName: string; // 注意分号结束
secondName: string;
}
function printName(name: FullName): void {
console.log(name.age);
console.log(name.firstName + '-' + name.secondName);
}
var yy = {
firstName: 'yu',
secondName: 'yuan',
age: 20
}
printName(yy)
// 传一个对象变量的时候,只需要包含firstName和secondName就行
// 我的理解:只会解析对象的firstName和secondName过去,虽然yy有age,但是方法内是拿不到的(针对ts,但js是可以直接打印的)
// 直接传一个对象,就只含firstName和secondName
interface FullName {
firstName: string; // 注意分号结束
secondName?: string; // 可选属性
}
// 函数类型接口:对方法传入的参数以及返回值进行约束
// 也就是说方法的参数和返回值必须按照接口来
interface formatInput {
(name: string, age: number): string
}
var handleInfo: formatInput = function (name: string, age: number): string {
return `我的名字叫${name},我今年${age}岁!`
}
console.log(handleInfo('张三', 20));
// 类类型接口:对类进行约束
interface Animal {
name: string;
eat(food: string): void;
}
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name
}
eat(): void {
// 接口要求参数,但是这里不加参数也可以
console.log(this.name + '吃东西...');
}
}
var d = new Dog('哈士奇')
d.eat()
// 继承接口
interface Animal {
eat(food: string): void
}
interface People extends Animal {
work(name: string): void
}
class Chinese implements People {
name: string
constructor(name: string) {
this.name = name
}
eat(food: string): void {
console.log(this.name + '正在吃' + food);
}
work(name: string): void {
console.log(this.name + '正在' + name);
}
}
var yy = new Chinese('yuwan')
yy.eat('花甲米线')
yy.work('学习Typescript')
// 可索引接口:对数组、对象进行约束(不常用)
interface UserArr {
[index: number]: string
}
var arr: UserArr = ['111', '222']
console.log(arr[0]);
6.范型
与any
相比,泛型支持类型校验,所以更好
本部分内容包括:范型定义
、泛型类
、泛型接口
// 定义范型
function getMyself<T>(a: T): T {
return a
}
getMyself<number>(5)
getMyself<string>('ssss')
// 泛型类
class Custom<T>{
nums: T[] = []
push(value: T): void {
this.nums.push(value)
}
min(): T {
var minVal: T = this.nums[0]
for (let i = 0; i < this.nums.length; i++) {
if (minVal > this.nums[i]) {
minVal = this.nums[i]
}
}
return minVal
}
}
var a = new Custom<number>()
a.push(1)
a.push(3)
console.log(a.min());
var b = new Custom<string>()
b.push('a')
b.push('f')
console.log(b.min());
// 泛型接口:两种写法
interface Iadd {
<T>(a: T): T
}
var getData: Iadd = function <T>(a: T): T {
return a
}
getData<number>(20)
getData<string>('20')
interface Iadd<T> {
(a: T): T
}
function getData<T>(val: T): T {
return val
}
var numGetData: Iadd<number> = getData
numGetData(20)
var strGetData: Iadd<string> = getData
strGetData('20')
// 利用泛型类实现添加用户表信息、其他表信息
class User {
username: string
password: string
constructor(username: string, password: string) {
this.username = username
this.password = password
}
}
class Goods {
name: string
price: number
constructor(name: string, price: number) {
this.name = name
this.price = price
}
}
class OptionClass<T>{
insert(obj: T): boolean {
console.log(obj);
return true
}
}
var op = new OptionClass<User>()
var yy = new User('yuwan', '123456')
op.insert(yy)
5-6综合运用
案例:封装MySQL、MongoDB、Mssql的底层库
要求:
- 支持mysql、MongoDB、mssql
- 各数据库都是增删查改操作
- 注重接口规范、以及代码重用
注:泛型类才能实现范型接口
interface iDatabase<T> {
insert(data: T): boolean;
update(data: T, id: number): boolean;
delete(id: number): boolean;
query(id: number): boolean
}
// 注:泛型类才能实现泛型接口
class Mysql<T> implements iDatabase<T>{
insert(data: T): boolean {
console.log('插入成功...');
console.log('插入的数据是:', data);
return true
}
update(data: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(id: number): boolean {
throw new Error("Method not implemented.");
}
query(id: number): boolean {
throw new Error("Method not implemented.");
}
};
class MongoDB<T> implements iDatabase<T>{
insert(data: T): boolean {
throw new Error("Method not implemented.");
}
update(data: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(id: number): boolean {
throw new Error("Method not implemented.");
}
query(id: number): boolean {
throw new Error("Method not implemented.");
}
}
class User {
username: string;
password: string;
constructor(username: string, password: string) {
this.username = username
this.password = password
}
}
var user = new User('yuwan', '123456')
var opMysql = new Mysql<User>() // 限制参数是user表
opMysql.insert(user)
7.模块
感觉和es6的一样,没什么变化!
// user.ts
export class User {
username: string;
password: string;
constructor(username: string, password: string) {
this.username = username
this.password = password
}
}
// index.ts
import { User } from './user'
// ...
8.命名空间
命名空间:内部模块,主要用于组织代码,避免命名冲突
模块:Typescript的外部模块简称,侧重代码复用,一个模块可能有多个命名空间
namespace mysql {
export var name: string = 'mysql的包...'
export function insert(): void {
console.log('mysql的操作方法...');
}
}
namespace mongodb {
export var name: string = 'mongodb的包...'
export function insert(): void {
console.log('mongodb的操作方法...');
}
}
mysql.insert()
mongodb.insert()
9.装饰器
定义:是一种特殊类型的声明,可以附加到类声明、方法、属性和参数上,可以修改类的行为(类似Java的注解)
常见分类:类装饰器、属性装饰器、方法装饰器、参数装饰器
写法:普通装饰器(无法传参)、装饰器工厂(可以传参)
本节内容包括:类装饰器的简单使用
、装饰器工厂
、装饰器重写类属性和方法
、属性装饰器
、方法装饰器
// 普通装饰器:扩展类的属性和方法,默认把class传过来
function Chinese(personClass: any) {
personClass.prototype.work = function () {
console.log(this.name + '在工作...');
}
}
@Chinese
class Person {
name: string;
constructor(name: string) {
this.name = name
}
}
var yy: any = new Person('yuwan')
yy.work()
console.log(yy);
// 高级用法:类似于高阶函数,传入参数
function Chinese(params: string) {
console.log(params);
return function (personClass: any) {
personClass.prototype.work = function () {
console.log(this.name + '在工作...');
}
}
}
@Chinese('你想知道我在干什么吗?')
class Person {
name: string;
constructor(name: string) {
this.name = name
}
}
var yy: any = new Person('yuwan')
yy.work()
console.log(yy);
// 高级用法:装饰器重写类的属性和方法
function Chinese(personClass: any) {
return class extends personClass {
// 重载Person的属性和方法
name = '哥哥'
work(): void {
console.log('装饰器:' + this.name + '在工作...');
}
}
}
@Chinese
class Person {
name: string | undefined;
constructor() {
this.name = '罗志祥'
}
work(): void {
console.log(this.name + '在工作...');
}
}
var yy: any = new Person()
yy.work() // 哥哥在工作
console.log(yy); // yy是个匿名类了,继承了Person
// 属性装饰器
function log(message: string) {
return function (target: any, propertyName: any) {
// target :对于静态成员是类的构造函数,对于实例成员是类的原型对象 propertyName:属性名
target[propertyName] = message
console.log(target)
}
}
class MyResponse {
@log('初值...') // 未实例化类也会调用该方法
message: string | undefined
}
var resp = new MyResponse()
// 方法参数器
function log(message: string) {
return function (target: any, methodName: any, desc: any) {
// target:类的静态成员来说是构造函数,实例成员来说是类的原型对象
// methodName:方成员名
// desc:成员属性描述符
target.message = message
target.run = function () { // 扩展类的成员
console.log('running...');
}
// 总结:很像python的高阶函数,使得可以在这自定义调用原error()
var origMethod = desc.value // 原方法体:function(...args){...}
desc.value = function (...args: any[]) {
console.log('装饰器执行前:',args);
args=args.map(item => String(item))
origMethod.apply(this, args) // 调用原来的error()方法
}
}
}
class MyResponse {
message: string | undefined
@log('嘻嘻')
error(...args: any[]): void {
console.log('装饰器执行后:', args);
}
}
var resp: any = new MyResponse()
resp.error(123, 'aaa', true)