配置
- tsc --init 生成tsconfig.json
- vscode 任务-运行任务 tsc:监视-tsconfig.json
数据类型
-
boolean, number, string, array, null, undefied, void
-
元组类型tuple
let tuple:[number, string] = [1, 's']
-
枚举类型enum
enum Color { red, blue, yellow = 5, } let color:Color = Color.yellow // 5 color = Color.yellow // 0, 未赋值则输出下标
-
任意类型any
-
null和undefined是其他(never)类型的子类型
-
void类型: ts中void类型表示没有任何类型,一般用于定义方法时,方法没有返回值
-
never类型:其他类型(null和undefined)的子类型
函数
// 函数声明
function run():string {
return '123'
}
// 匿名表达式
var run2 = function():string {
return '123'
}
// ts中定义方法传参
function getInfo(name: string, age: number):string {
return `${name}:${age}`
}
// 方法可选参数(age可传,可不传)
// 可选参数要放在所有参数的最后
function getInfo(name: string, age?: number):string {
if (age) {
return `${name}:${age}`
}
return `${name}`
}
// 默认参数
function getInfo(name: string, age: number = 20):string {
if (age) {
return `${name}:${age}`
}
return `${name}`
}
// 剩余参数
function sum(a: number, b:number, c:number, d:number):number {
return a + b + c + d;
}
可改为
function sum(...res: number[]):number {
return res.reduce((acc, cur) => acc + cur, 0)
}
// ts函数重载
function getInfo(name: string): string;
function getInfo(age: number): number;
function getInfo(arg: any): any {
return 123;
}
// 箭头函数
ts中的类
- 类的定义、继承
// es5
function Person(name) {
this.name = name;
this.run = function () {
console.log(this.name)
}
}
var p = new Person('张三')
p.run()
// ts中定义类
class Person {
name: string; // 属性,省略了public关键词
constructor(name:string) { // 构造函数,实例化类时触发的方法
this.name = name;
}
getName():string {
return this.name
}
setName(name: string):void{
this.name = name
}
}
var p = new Person('张三')
p.setName('李四')
alert(p.getName())
// ts中实现继承 extends, super
class Person {
name: string; // 属性,省略了public关键词
constructor(name:string) { // 构造函数,实例化类时触发的方法
this.name = name;
}
run():string {
return `${this.name} is running`
}
}
class Web extends Person {
constructor(name: string) {
super(name)
}
}
var w = new Web('lisi')
console.log(w.run())
// ts中继承的探讨
class Person {
name: string; // 属性,省略了public关键词
constructor(name:string) { // 构造函数,实例化类时触发的方法
this.name = name;
}
run():string {
return `${this.name} is running`
}
}
class Web extends Person {
constructor(name: string) {
super(name)
}
run():string {
return '子类' //父类中也有同名方法,则调用子类的方法
}
work() {
alert(`${this.name}在工作`) // this指向web实例
}
}
var w = new Web('lisi')
console.log(w.run())
类里的修饰符
- ts里定义属性的时候,给我们提供了三种修饰符
/*
public:公有 在类里面,子类和类外面都可以访问
protected:保护类型 在类里面、子类里面可以访问,在类外部没法访问
private:私有 在类里面可以访问,子类和类外部都没法访问
*/
// public
// 属性不加任何修饰符为public
// 类外部访问公有属性
class Person {
public name: string;
constructor(name:string) {
this.name = name;
}
}
var p = new Person('lala');
console.log(p.name)
// protected
// 在子类中访问
class Person {
protected name: string; // 属性,省略了public关键词
constructor(name:string) { // 构造函数,实例化类时触发的方法
this.name = name;
}
}
class Web extends Person {
constructor(name: string) {
super(name)
}
run():string {
return `${this.name}lalalla`
}
}
var w = new Web('ab');
console.log(w.run())
// private 只能在类内部访问
class Person {
private name: string; // 属性,省略了public关键词
constructor(name:string) { // 构造函数,实例化类时触发的方法
this.name = name;
}
}
静态属性 静态方法
- es5
// 实例方法
function Person() {
this.run1 = function() {
...
}
}
// 静态方法
Person.run2 = function() {
}
// 静态属性
Person.name = 'lalal'
var p = new Person();
p.run1()
Person.run2()
-
已经有实例方法,为啥要有静态方法
// jquery function $(element) { return new Base(element) } function Base (element) { this.element = document.getElementById(element); this.css = function (attr, val) { this.element.style.attr = val } } // 实例方法 $('#box').css('color', 'red') // 静态方法 $.get('url', function() {...})
-
ts里静态方法和属性
class Person {
public name: string
public age: number = 20
// 静态属性
static sex: string = '男'
constructor(name:string) {
this.name = name;
}
// 实例方法
run() {
alert(`${this.name}is running`)
}
work() {
alert(`${this.name}is working`)
}
// 静态方法 里面没法直接调用类里面的属性!!!
static print() {
alert(`print+${Person.sex}`)
}
}
Person.print()
多态 :父类定义一个方法不去实现,让继承他的子类去实现,每一个子类有不同的表现
- 多态属于继承
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 + '吃鱼'
}
}
var cat = new Cat('cattie')
alert(cat.eat())
ts中的抽象类,提供其他类继承的基类,不能直接被实例化
- 用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并必须在派生类中实现
- abstract抽象方法只能放在抽象类里面
- 抽象类和抽象方法用来定义标准
// Animal类的子类必须包含eat方法
abstract class Animal {
public name: string;
constructor(name:string) {
this.name = name
}
abstract eat():any;
}
// 抽象类的子类必须实现抽象类里的抽象方法
class Dog extends Animal {
constructor(name:string) {
super(name)
}
eat() {
return this.name + 'something'
}
}
var d = new Dog('abctest+')
alert(d.eat())
ts中的接口
- 定义标准(包括属性,函数,可索引, 类等)
属性接口 对json的约束
// 接口 行为和动作的规范 对批量方法传入参数进行约束
// 对传入对象的约束, 属性接口
interface FullName {
firstName: string; // 注意!!分号结束
secondName: string;
}
function printName(name: FullName) {
// 必须传入对象,必须包含fistName,secondName
console.log(`${name.firstName} ${name.secondName}`)
// console.log(`${name.firstName} ${name.secondName} ${name.age}`) // name.age 报错
}
// 直接传入参数,则有且仅有firstName和secondName,否则报错
// printName({ firstName: 'zhang', secondName: 'san' age: 20 }) // age报错
// 定义在外面 再传入,则必须包含firstName和secondName,多的参数也行, 但在方法里调用fullName不存在的属性也会报错
const obj = {
firstName: 'zhang',
secondName: 'san',
age: 20
}
printName(obj)
- 接口 可选属性
interface FullName {
firstName: string;
secondName?: string;
}
函数类型接口: 对方法传入的参数,以及返回值进行约束 (可批量约束)
interface encrypt {
(key: string, val: string):string
}
var md5:encrypt = function(key: string, val: string):string {
return `${key} + ${val}`
}
console.log(md5('test', '123'))
可索引接口,对数组/对象的约束
// 可索引接口 对数组的约束
interface UserArr {
[index: number]: string
}
var arrTest: UserArr = ['123', '112']
console.log(arrTest[0])
// 可索引接口 对对象的约束
interface UserObj {
[index: string]: string
}
var usrObj:UserObj = {
name: '20'
}
console.log(usrObj.name)
类类型接口
// 类类型接口:对类的约束 和抽象类有点类似
interface Animal {
name: string;
eat(str: String):void;
}
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
// 必须有eat方法,eat方法可不传参数
eat() {
console.log(this.name + '吃粮食')
}
}
var d = new Dog('xxiaohei')
d.eat()
class Cat implements Animal {
name: string;
constructor(name: string) {
this.name = name
}
eat(food: string) {
console.log(`${this.name} + ${food}`)
}
}
var c = new Cat('miaomiao')
c.eat('laoshu')
接口的扩展、接口的继承(接口可以继承接口)
// 例子一
interface Animal {
eat():void
}
interface Person extends Animal {
work():void
}
class Web implements Person {
public name: string;
constructor(name:string) {
this.name = name
}
eat() {
console.log(`${this.name} --- chi`)
}
work() {
console.log(`${this.name} --- work`)
}
}
var ww = new Web('webbbb')
ww.eat()
ww.work()
// 例子二 继承 + 实现(接口扩展)
interface Animal {
eat():void
}
interface Person extends Animal {
work():void
}
class Programmer {
public name: string;
constructor(name:string) {
this.name = name
}
coding(code: string) {
console.log(`${this.name} + coding... + ${code}`)
}
}
class Web extends Programmer implements Person {
constructor(name:string) {
super(name)
}
eat() {
console.log(`${this.name} --- chi`)
}
work() {
console.log(`${this.name} --- work`)
}
}
var ww = new Web('webbbb')
ww.eat()
ww.work()
ww.coding('ts')
泛型
- 解决类 ,接口,方法的复用性, 以及对不特定数据类型的支持
- 泛型可以支持不特定的类型数据,要求:传入的参数和返回的参数一致
泛型的定义,泛型函数
// T表示泛型 具体什么类型是调用这个方法的时候决定的
function getData<T>(value:T):T {
return value
}
// function getData<T>(value:T):any {
// return 'test'
// }
// getData<Number>('test'); 错误写法
getData<Number>(123); // 参数必须是number
泛型类
// 最小堆算法,需要同时支持返回数字和字符串两种类型,通过类的泛型来实现
class MinClass<T> {
public list: T[] = []
add(num:T) {
this.list.push(num)
}
min():T {
var minNum = this.list[0]
for (let i = 0; i < this.list.length; i++) {
if (this.list[i] < minNum) {
minNum = this.list[i]
}
}
return minNum
}
}
var m = new MinClass<number>() // 实例化类,且制定T代表number
m.add(2)
m.add(3)
m.add(4)
alert(m.min())
var m2 = new MinClass<string>()
m2.add('44')
m2.add('a')
m2.add('v')
alert(m2.min())
泛型接口
// 1. 第一种定义泛型接口的方法
interface ConfigFn {
<T>(val:T):T
}
var getData:ConfigFn = function<T>(value: T) {
return value
}
getData<string>('123')
// 2.第二种定义泛型接口的方法
interface ConfigFn<T> {
(val:T):T;
}
function getData<T>(value: T):T {
return value
}
var myGetData:ConfigFn<string> = getData;
myGetData('20')
把类作为参数类型的泛型类
- 先定义个类
- 把类作为参数来约束数据传入的类型
功能一
class User {
username: string | undefined;
password: string | undefined;
}
class MysqlDb {
add(user: User): boolean {
console.log(user)
return true
}
}
var u = new User()
u.username = 'zhangsan'
u.password = '123456'
var db = new MysqlDb()
db.add(u)
功能二
class ArticleCate {
title: string | undefined;
desc: string | undefined;
status: number | undefined;
}
class MysqlDb {
add(info: ArticleCate): boolean {
console.log(info)
return true
}
}
var a = new ArticleCate()
a.title = '国内'
a.desc = '国内新闻'
a.status = 1
var DB = new MysqlDb()
DB.add(a)
但mySqlDb重复封装了,通过泛型解决
// 操作数据库的泛型类
class MysqlDb <T> {
add(info: T): boolean {
console.log(info)
return true
}
update(info: T, id: number):boolean {
console.log(info)
console.log(id)
return true
}
}
// 1.定义一个user类和数据库进行映射
class User {
username: string | undefined;
password: string | undefined;
}
var u = new User()
u.username = 'zhangsan'
u.password = '123456'
var DB = new MysqlDb<User>()
DB.add(u)
// 1.定义一个ArticleCate类和数据库进行映射
class ArticleCate {
title: string | undefined;
desc: string | undefined;
status: number | undefined;
constructor(params: {
title?: string,
desc?: string,
status?: number ,
}) {
this.title = params.title
this.desc = params.desc
this.status = params.status
}
}
var a = new ArticleCate({
title: '分类',
desc: '111'
})
var DB2 = new MysqlDb<ArticleCate>()
DB2.add(a)
DB2.update(a, 2)
ts类型,接口,类,泛型综合使用
interface DBI<T> {
add(info: T):boolean;
update(info: T, id: number):boolean;
delete():boolean;
get(id: number): any[]
}
// 定义一个操作mySql数据库的类 注意:要实现泛型接口,这个类也应该是一个泛型类
class MysqlDb<T> implements DBI<T> {
add(info: T): boolean {
console.log(info)
return true
}
update(info: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
var list = [
{
title: 'xxxx',
desc: 'xxx1'
},
{
title: 'xxxx',
desc: 'xxx1'
},
]
return list
}
}
// 定义一个操作mySql数据库的类 注意:要实现泛型接口,这个类也应该是一个泛型类
class MssqlDb<T> implements DBI<T> {
add(info: T): boolean {
console.log(info)
return true
}
update(info: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
var list = [
{
title: 'xxxx',
desc: 'xxx1'
},
{
title: 'xxxx',
desc: 'xxx1'
},
]
return list
}
}
// 操作用户表 定义一个user类和数据表的映射
class User {
username: string | undefined;
password: string | undefined;
}
var u = new User()
u.username = 'zhangsan'
u.password = '123456'
var oMySql = new MysqlDb<User>(); // 用类约束传入参数的合法性
oMySql.add(u)
console.log(oMySql.get(4))
var oMsSql = new MssqlDb<User>()
oMsSql.add(u)
console.log(oMsSql.get(1))
ts 模块化封装
模块的定义,引用
// db.ts
var dbUrl = 'xxx'
function getData():any[] {
console.log('获取数据库数据')
var list = [
{
title: '222'
}, {
title: '333'
}
]
return list
}
function saveData() {
console.log('保存')
}
export {
dbUrl,
getData,
saveData
}
// export default getData // export default在一个模块中只能用一次,引入时import getData from ’xxxx/xxx‘
// index.ts
import { getData as get, saveData } from './modules/db'
get()
saveData()
应用举例:封装db库
// modules/db.ts
interface DBI<T> {
add(info: T):boolean;
update(info: T, id: number):boolean;
delete():boolean;
get(id: number): any[]
}
export class MssqlDb<T> implements DBI<T> {
add(info: T): boolean {
console.log(info)
return true
}
update(info: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
var list = [
{
title: 'xxxx',
desc: 'xxx1'
},
{
title: 'xxxx',
desc: 'xxx1'
},
]
return list
}
}
// model/user.ts
import { MssqlDb } from '../modules/db'
class UserClass {
username: string | undefined;
password: string | undefined;
}
var UserModel = new MssqlDb<UserClass>(); // 用类约束传入参数的合法性
export {
UserClass,
UserModel
}
// index.ts
import { UserClass, UserModel } from './model/user'
import {ArticleClass, ArticleModel } from './model/article'
var user = new UserClass();
user.username = 'zhangsan'
user.password = '123344'
UserModel.add(user)
var res = UserModel.get(123)
console.log(res)
命名空间 命名空间块化
namespace A {
// ...
}
namespace B {
// ...
export class Dog {
name: string;
constructor(name:string) {
this.name = name
}
}
}
// 调用命名空间中的方法,或类,需要在namespace中暴露export出来
var d = new B.Dog('jfsldjf')
console.log(d)
可将命名空间当作一个模块直接暴露出来
// modules/a.ts
export namespace A {
// ...
}
// index.ts
import { A } from 'xxxx'
var d = new A.dog('test')
命名空间和模块的区别:命名空间主要用于组织代码,避免命名冲突;模块侧重代码的重用,一个模块可能会有多个命名空间
装饰器
装饰器:是一种特殊类型的声明,能够被附加到类声明,方法,属性,或参数上,可以修改类的行为
通俗的讲,装饰器就是一个方法,可以注入到类,方法,属性参数上来扩展类,属性,方法,参数的功能;
常见装饰器有:类装饰器,属性装饰器,方法装饰器,参数装饰器
装饰器的写法:普通装饰器(无法传参);装饰器工厂(可传参)
类装饰器
普通装饰器(无法传参)
// 类装饰器,在类声明之前被声明(紧接着类声明),应用于类构造函数,可用来监视、修改、或替换类定义
// 装饰器
function logClass(params:any) {
console.log(params) // params 就是当前类
params.prototype.apiUrl = 'xxxx'
params.prototype.run = function() {
console.log('run method')
}
}
@logClass
class HttpClient {
constructor() {
}
getData() {
}
}
var http: any = new HttpClient()
console.log(http.apiUrl)
http.run()
装饰器工厂(可传参数)
// 装饰器工厂
function logClass(params: string) {
return function(target: any) { // target为类
// console.log(target, params)
target.prototype.apiUrl = params
}
}
@logClass('http://hello')
class HttpClient {
constructor() {
}
getData() {
}
}
var http:any = new HttpClient()
console.log(http.apiUrl)
类装饰器:下面是一个重载构造函数的例子, (修改当前类的构造函数或方法,可看为固定用法)
function logClass(target:any) {
console.log(target)
return class extends target {
apiUrl: any = '修改后数据'
getData() {
console.log(`${this.apiUrl} + 修改后的`)
}
}
}
@logClass
class HttpClient {
public apiUrl: string | undefined;
constructor() {
this.apiUrl = '我是构造函数里面的apiUrl'
}
getData() {
console.log(this.apiUrl)
}
}
var http = new HttpClient()
http.getData()
属性装饰器
// 属性装饰器
// 属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数
// 1. 对静态成员来说是类的构造函数,对实例成员来说是类的原型对象
// 2. 成员的名字
function logProperty(params:any) {
return function (target:any, attr: any) {
console.log(target, attr)
target[attr] = params
}
}
@logClass('http://hello')
class HttpClient {
@logProperty('newUrl')
public url: any | undefined
constructor() {
}
getData() {
console.log('getData===>', this.url)
}
}
var http = new HttpClient()
http.getData()
方法装饰器
方法装饰器 会应用到方法的属性描述符上,可以用来监视,修改,或者替换方法定义
方法装饰器会在运行时,传入下列三个参数
1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
2. 成员的名字
3. 成员的属性描述符
方法装饰器一: 修改当前实例的属性和方法
function get(params:any) {
return function(target:any, methodName: any, desc:any) {
console.log(target, methodName, desc) // 仍可改变类原型上的方法和属性
target.apiUrl = 'apiUro'
target.run = function() {
console.log('run')
}
}
}
class HttpClient {
public url: any | undefined
constructor() {
}
@get('htttp://dksjflsjkf')
getData() {
console.log('getData===>', this.url)
}
}
var http:any = new HttpClient()
console.log(http.apiUrl)
http.run()
方法装饰器二: 修改当前方法
function get(params:any) {
return function(target:any, methodName: any, desc:any) {
console.log(target, methodName, desc.value)
// 修改装饰器的方法,把装饰器方法里面传入的所有参数改为string类型
// 1. 保存当前方法
var oMethod = desc.value;
desc.value = function(...args: any[]) {
args = args.map(val => String(val))
console.log(args)
// 2. 调用原来的旧方法(看是否需要直接覆盖,可省略)
oMethod.apply(this, args)
}
}
}
class HttpClient {
public url: any | undefined
constructor() {
}
@get('htttp://dksjflsjkf')
getData(...args:any[]) {
console.log('我是getData', args)
}
}
var http:any = new HttpClient()
http.getData(123, 'xdd')
方法参数装饰器
参数装饰器表达式会在运行时当作函数被调用,可用使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数
1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
2. 方法的名字
3. 参数在函数参数列表中的索引
function logParam(params: any) {
return function(target:any, methodName: any, paramsIndex:any) {
// console.log(params)
// console.log(target, methodName, paramsIndex)
target.apiUrl = params
}
}
class HttpClient {
public url: any | undefined
constructor() {
}
getData(@logParam('uuid') uuid:any) {
// console.log(uuid)
}
}
var http:any = new HttpClient()
console.log(http.apiUrl)
http.getData(123456)
装饰器的执行顺序
- 属性 > 方法 > 方法参数 > 类装饰器
- 有多个同样的装饰器,则会先执行后面的
function logClass1(params:string) {
return function(target:any) {
console.log('类装饰器1')
}
}
function logClass2(params:string) {
return function(target:any) {
console.log('类装饰器2')
}
}
function logAttr(params?:string) {
return function(target:any, attr: any) {
console.log('属性装饰器')
}
}
function logMethod(params?:string) {
return function(target:any, methodName: any, desc: any) {
console.log('方法装饰器')
}
}
function logParam1(params?: any) {
return function(target:any, methodName: any, paramsIndex:any) {
console.log('方法参数装饰器1')
}
}
function logParam2(params?: any) {
return function(target:any, methodName: any, paramsIndex:any) {
console.log('方法参数装饰器2')
}
}
@logClass1('http://1')
@logClass2('http://2')
class HttpClient {
@logAttr()
public url: any | undefined
constructor() {
}
@logMethod()
getData() {
return true
}
setData(@logParam1() attr1:any, @logParam2() attr2: any) {
}
}
var http:any = new HttpClient()
// 打印结果是
/ *
属性装饰器
方法装饰器
方法参数装饰器2
方法参数装饰器1
类装饰器2
类装饰器1
*/
网友评论