一 安装
npm install -g typescript
二 TS编译成ES5/ES6
浏览器不支持ts语法,所以需要编译成es5或es6
tsc index.ts
三 Typescript 开发工具 Vscode 自动编译.ts文件
1.创建tsconfig.json文件 tsc --init 生成配置文件
tsc --init
2.配置json文件,改为js地址
如果有报错可以参考这连接------点我啊
四 ts数据类型
- boolean
- number
- string
- array
- tuple(元组)
- enum((枚举)
- any(任意)
- null 和 undefined
- void
- never
ts校验目的是为了代码更加规范,以往我们设定了常量可以随意书写不同类型,但在ts中,从一开始就写好类型后不允许变更,否则报错.
HTML正确引入js文件后试运行
数据类型与函数的定义
// ts定义数组的方式
// 第一种
let arr: String[] = ['jjhh', '2222', 'false']
// 第二种
let arr2: Array<number> = [11, 22, 33, 44]
console.log(arr);
console.log(arr2);
// 元组类型(tuple),属于数组的一种
// 元组就是可以指定数组里面每个元素的类型
let arr3: [String, Number, boolean] = ['11', 22, true]
console.log(arr3);
// 枚举类型(enum)
// 随着计算机的不断普及,程序不仅只是用于数值计算,还更广泛地用于处理非数值的数据.
// 例如:性别/月份/星期几/颜色/单位名/学历/职业等,都不是数值数据.
// 在其他程序设计语言中,一般用一个数值来表达某一个状态,则程序就很容易阅读和理解
// 也就是说,实现考虑到某一变量可能取的值,尽量用自然语言中含义清除的单词来表示它
// 的每一个值,这种方法称为枚举方法,用这种方法定义的类型称枚举类型
// enum 枚举名{
// 标识符[=整型常数],
// 标识符[=整型常数],
// ...true
// 标识符[=整型常数],
// }
// 例:pay 0 未支付 1支付 2交易成功
enum pay {
未支付 = 0,
支付 = 1,
交易成功 = 2
}
let p: pay = pay.未支付
console.log(p);//0
// 如果不赋值默认输出索引
enum Color {
red, bule = 5, orange }
let c: Color = Color.red
let c1: Color = Color.bule
let c2: Color = Color.orange
console.log(c);//0
console.log(c1);//5
console.log(c2);//6
// 任意类型(any)
let a: any = 123
a = 'ikhh'
console.log(a);//ikhh
// undefined
let udf: undefined;//定义没赋值不会报错
console.log(udf);//undefined
let udf1: Number | undefined = 777
console.log(udf1);//777
// void类型:ts中的void表示没有任何类型,一般用于定义方法的时候方法没有返回值
function run(): void {
console.log('表示方法没有返回任何类型');
}
run()
// 定义函数的方法
// 函数声明法
function run1(): String {
return '必须返回字符串'
}
console.log(run1());
// 匿名函数法
let run2 = function (): Number {
return 134
}
console.log(run2());
// 定义方法传参
function run3(name: String, age: Number): boolean {
return true
}
console.log(run3('字符串', 99));
// 方法可选参数
// es5里面方法的实参和形参可以不一样,但在ts中必须一样,如果不一样需要配置可选参数
// (多加一个?问号)
// 注意:可选参数必须配置到参数的最后面
function run4(name: String, age?: Number): boolean {
return true
}
console.log(run4('字符串'))
// 默认参数
//es5里面没法设置默认参数,es6和ts中都可以设置默认参数
function run5(name: String, age: Number = 20): String {
return `${
name}----${
age}`
}
console.log(run5('字符串'))//字符串----20
// 剩余运算符
// 三点运算法:方法一
function sum(...result: number[]): number {
let sum = 0
result.map(item => sum += item)
return sum
}
console.log(sum(1, 2, 3, 4));//10
// 方法二
function sum2(a: number, b: number, ...result: number[]): number {
let sum = 0
result.map(item => sum += item)
return sum
}
console.log(sum2(1, 2, 3, 4));//7
// 函数的重载
//Java中方法的重载:重载指的是两个或者两个以上同名函数,但它们的参数不一样,这是会出现函数重载的情况
//ts中的重载:通过为同一个函数提供多个函数类型定义来试下多种功能的目的
// ts为了兼容es5以及es6重载的写法和Java中有区别
function getInfo(name: String): string
function getInfo(age: Number): Number
function getInfo(str: any): any {
if (typeof str === 'string') {
return `我的名字是${
str}`
} else {
return `我的年龄是${
str}`
}
}
console.log(getInfo('山竹'));
ts中的类
es5中的类和静态方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./js/index.js"></script>
</head>
<script>
// es5里面的类
function Person() {
//实例方法
this.name = '山竹',
this.age = 18
}
var p = new Person
console.log(p.age);//18
// 构造函数与原型链里面添加办法
function Person1() {
this.work = function () {
console.log('在工作');
}
}
Person1.prototype.sex = '女';
Person1.prototype.run = function () {
console.log('在运动');
}
var p1 = new Person1
p1.work();//在工作
p1.run();//在运动
// 类里面的静态方法
function Person2() {
}
Person2.read = function () {
console.log('read');
}
Person2.read()//read
// es5中的继承
function Person3() {
this.work = function () {
console.log('在工作');
}
}
Person3.prototype.sex = '女';
Person3.prototype.run = function () {
console.log('在运动');
}
// Web类继承Person类 原型链+对象冒充的组合继承模式
function web() {
Person3.call(this)//对象冒充实现继承
}
var w = new web()
w.work()//在运动,对象冒充可以继承构造函数里面的属性和方法
// w.run()//报错,没法继承原型链
// 原型链实现继承
// 既可以继承构造函数的方法也可以继承原型链上的属性和方法
// 但实例化子类的时候没法给父类传参
function Person4() {
this.work = function () {
console.log('在工作');
}
}
Person4.prototype.sex = '女';
Person4.prototype.run = function () {
console.log('在运动');
}
// Web类继承Person类 原型链+对象冒充的组合继承模式
function Web1() {
}
Web1.prototype = new Person4()
var w1 = new Web1()
w1.work()
</script>
<body>
</body>
</html>
ts中的类
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(n: String) {
//构造函数 实例化类的时候触发的方法
this.name = n
}
run(): void {
alert(this.name)
}
}
let p = new Person('山竹')
p.run()
ts中定义类与类传值
ts中实现继承
类里面的修饰符
// ts里面定义属性的时候给我们提供了三种修饰符
/**
* public :共有 在类里面/子类/类外面都可访问
* protected :保护类型 在类里面/子类里面都可访问,类外部没法访问
* private :私有 在类里面可以访问,子类/类外部都没法访问
*
* 属性不加修饰符默认为共有
*/
// 公有属性
class Person {
public name: String;//公有属性
constructor(name: String) {
this.name = name
}
run(): String {
return this.name
}
}
class Web extends Person {
constructor(name: String) {
super(name)
}
}
let w = new Web('山竹')
console.log(w.run());
保护属性
私有属性
ts中静态属性 静态方法 抽象类 多态
静态方法
静态方法没办法直接调用类里面的属性,除非实例化,或改为静态属性
多态
父类定义一个方法不去实现,让继承它的子类去实现,每一个子类有不同的表现
多态也是继承的一种表现
class Animal {
name: String;
constructor(name: String) {
this.name = name
}
eat() {
//具体吃什么还不知道
console.log('吃的方法');
}
}
// 第一个子类继承
class Dog extends Animal {
constructor(name: String) {
super(name)
}
eat(): String {
return `${
this.name}吃狗粮`
}
}
let d = new Dog('狗狗')
console.log(d.eat());
// 第二个子类继承
class Cat extends Animal {
constructor(name: String) {
super(name)
}
eat(): String {
return `${
this.name}吃猫粮`
}
}
let c = new Cat('猫猫')
console.log(c.eat());
抽象方法
typeScript中的抽象类:它是提供其他类继承的基类,不能直接被实例化
用abstract关键字定义抽象类和抽象方法,抽象类中的方法不包含具体实现并且必须要派生类中实现
abstract方法只能放在抽象类里面
抽象类和抽象方法来定义标准 Animal这个类要求它的子类必须包含eat方法
abstract class Animal {
name: String;
constructor(name: String) {
this.name = name
}
abstract eat(): any
}
// 第一个子类继承
class Dog extends Animal {
constructor(name: String) {
super(name)
}
eat(): String {
return `${
this.name}吃狗粮`
}
}
let d = new Dog('狗狗')
console.log(d.eat());
接口的概念
接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用.接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里面方法的实现细节,它只规定这批类里面必须提供某些方法,提供这些方法的类就可以满足实际需求,ts中的接口类似于Java,同时还增加了更灵活的接口类型,包括属性/函数/可索引和类.
定义标准
typeScript中的接口
1.属性类接口
2.函数类型接口
3.可索引接口
4.类类型接口
5.接口扩张
1.属性接口
ts自定义方法传入参数,对JSON进行约束
// 1.ts自定义方法传入参数,对JSON进行约束
function printLabel(labelInfo: {
label: string }): void {
console.log('printLabel');
}
printLabel({
label: '山竹回家了' })
// 2.对批量方法传入参数进行约束
// 接口:行为和动作的规范,对批量方法机型约束
// interface定义接口
interface FullName {
firstName: string;//以;结束
secondName: string;
}
function printName(name: FullName) {
//必须传入对象firstName secondName
console.log(name.firstName + '--' + name.secondName);
}
function printInfo(info: FullName) {
//必须传入对象firstName secondName
console.log(info.firstName + '--' + info.secondName);
}
let obj = {
firstName: '山竹',
secondName: '回家了'
}
// 传入的参数必须包含firstName和secondName
printName(obj)
printInfo({
firstName: '大山竹',
secondName: '又回家了'
})
// 3.接口,可选属性,加个问号
interface FullName2 {
firstName: string;//以;结束
secondName?: string;
}
function printName2(name: FullName2) {
//必须传入对象firstName secondName
console.log(name);
}
printName2({
firstName: '对,没错,又是山竹'
})
ajax封装
// ajax封装
/**
* $.ajax({
* type:'GET',
* url:'test.json',
* data:{},
* dataType:'json'})
*/
interface Config {
type: string;
url: string;
data?: string;
dataType: string
}
function ajax(config: Config) {
let xhr = new XMLHttpRequest();
xhr.open(config.url, config.url, true);
xhr.send(config.data);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log('chengong');
if (config.dataType == 'json') {
JSON.parse(xhr.responseText)
} else {
console.log(xhr.responseText);
}
}
}
}
ajax({
type: 'get',
data: '000',
url: '1111',
dataType: 'json'
})
2.函数类型接口
对参数与返回值进行约束,批量约束
// 函数类型接口:对方法传入的参数 以及返回值进行约束 批量
// 加密的函数类型接口
interface encrypt {
(key: string, value: string): string
}
let md5: encrypt = function (key: string, value: string): string {
return key + value
}
console.log(md5('name', '山竹'));
3.可索引接口:数组/对象的约束(不常用)
// 可索引接口----对数组约束
interface userArr {
[index: number]: string
}
let arr: userArr = ['山竹', '回家了']
console.log(arr[0]);
// 可索引接口----对对象约束
interface userObj {
[index: number]: string
}
let obj: userObj = ['大山竹', '回家了']
console.log(obj[0]);
4.类类型接口
对类的约束,与抽象类相似
// 类类型接口
interface Animal {
name: string;
eat(str: string): void
}
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name
}
eat() {
console.log(this.name + '吃狗粮');
}
}
let d = new Dog('小黑')
console.log(d);
接口扩展:接口可以继承接口
// 接口可以继承接口
// 定义一个接口
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 + code);
}
}
// 类继承并调用
// implements是一个类实现一个接口用的关键字.实现一个接口,必须实现接口中的所有方法。
class Web extends Programmer implements Person {
constructor(name: string) {
super(name)
}
eat() {
console.log(this.name + '喜欢吃馒头');
}
work() {
console.log(this.name + '写代码');
}
}
let w = new Web('山竹')
w.eat()
w.work()
w.coding('在疯狂写代码')
效果
泛型
泛型:软件工程中,我们不仅要创造一致的定义良好的API,同时也要考虑可重用行.组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时可以提供十分灵活的功能.
在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据.这样用户就可以以自己的数据类型来使用组件.
通俗理解:泛型就是解决 类 接口 方法的复用性,以及对不特定数据类型的支持.
1.泛型的定义与泛型函数
// 泛型:可以支持不特定的数据类型
// 要求:传入的参数和返回的参数一致
// T表示泛型,具体什么类型是调用这个方法的时候决定的
function getData<T>(value: T): T {
return value
}
getData<number>(123)
getData<String>('123')
2.泛型类
// 类的泛型
class MinClas<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 m = new MinClas<number>()
m.add(8)
m.add(89)
m.add(3)
console.log(m.min());
3.泛型接口
//泛型的第一种写法
interface ConfigFn {
<T>(value: T): T
}
let getData: ConfigFn = function <T>(value: T): T {
return value
}
getData<String>('山竹')
getData<Number>(67868)
// 泛型的第二种写法
interface ConfigFn2<T> {
(value: T): T
}
function getData2<T>(value: T): T {
return value
}
let myGetData2: ConfigFn2<string> = getData2;
myGetData2('20')
4.把类作为参数类型的泛型类
/**
* 定义一个User的类,这个类的作用就是映射数据库字段
* 然后定义一个MysqlDb的类,这个类用于操作数据库
* 然后把User类作为参数传入到MysqlDb中
*/
class User {
username: string | undefined;
password: string | undefined;
}
// class MysqlDb {
// add(user: User): boolean {
// console.log(user);
// return true
// }
// }
// 操作数据库的泛型类
class MysqlDb<T> {
add(user: T): boolean {
console.log(user);
return true
}
}
let u = new User()
console.log(u, 999);
u.username = '张三'
u.password = '11111'
let Db = new MysqlDb<User>()//这里约束,下面ADD就不可以随意传入
Db.add(u)
ts模块
1.创建module文件夹在js文件夹中
创建一个使用export导出的函数
// 方式1:
// export function getData(): any[] {
// console.log(123);
// return []
// }
// 方式2:
function getData(): any[] {
console.log(123);
return []
}
export {
getData
}
使用import引入并使用
/**
* 模块的概念(官方):
* 关于术语的一点说明:请务必注意一点,ts1.5里术语名已经发生了变化.'内部模块'现在称作'命名空间'.
* '外部模块'现在则简称为'模块',模块在其自身的作用域里执行,而不是在全局作用域里;
* 这意味着定义一个模块里的变量,函数,类等等在模块外部是不可见的.除非你明确地使用export形式之一导出它们.
* 相反,如果想使用其他模块导出的变量,函数,类,接口等的时候,你必须要导入它们,可以使用import形式之一.
*
* (自己理解):
* 我们可以把一些公共的功能单独抽离成一个文件作为模块.
* 模块里面的变量 函数 类等默认是私有的,如果我们要在外部访问模块里面的数据(变量,函数,类),
* 暴露后我们通过import引入模块就可以使用模块里面暴露的数据(变量,函数,类)
*/
// import { getData } from "./js/module";
import {
getData as get } from "./js/module";//简写
get()
在cmd打印结果
命名空间
/**
* 命名空间:
* 在代码量较大的情况下,为了避免各种变量命名相冲突,可将想死功能的函数,类,接口等防止在命名空间内
* 同Java的包,.net的命名空间一样,ts的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象.
* 命名空间内的对象通过export导出
*
* 命名空间和模块的区别:
* 命名空间:内部模块,主要用于组织代码,避免命名冲突.
* 模块:ts的外部模块的简称,侧重代码的复用,一个模块里可能会有多个命名空间.
*/
// 使用namespace定制命名空间,使用export导出
namespace A {
interface Animal {
name: string;
eat(): void
}
export class Dog implements Animal {
name: string;
constructor(theName: string) {
this.name = theName
}
eat() {
console.log(this.name, '吃山竹');
}
}
}
namespace B {
interface Animal {
name: string;
eat(): void
}
export class Dog implements Animal {
name: string;
constructor(theName: string) {
this.name = theName
}
eat() {
console.log(this.name, '吃山竹');
}
}
}
let a = new A.Dog('山竹')
a.eat()
let b = new B.Dog('超级无敌大山竹')
b.eat()
装饰器
- 执行顺序:属性>方法>类
- 多个装饰器时从后到前
1.打开experimentalDecorators
1.类装饰器
/**
* 装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为.
*
* 通俗的讲装饰器就是一个方法,可以注入到类/方法/属性参数上来扩展类/属性/方法/参数的功能.
*
* 常见的装饰器有:类装饰器/属性装饰器/方法装饰器/参数装饰器
*
* 装饰器的写法:普通装饰器(无法传参)/装饰器工厂(可传参)
*
* 装饰器是过去几年中js最大的成就之一,已是es7的标准特性之一
*
*/
// 1.类装饰器:类装饰器在类声明之前被声明(紧靠着类声明).类装饰器应用于类构造函数,可以用来监视,修改或替换类定义.
// 传入一个参数
// 装饰器:不修改原类的情况下添加功能
// 1.普通装饰器
// function logClass(params: any) {
// console.log(params);//params就是当前类
// params.prototype.apiUrl = '动态添加的属性';//扩展类的属性
// params.prototype.run = function () {
// console.log('我是一个run方法');
// }
// }
// // 使用装饰器
// @logClass
// class HttpClient {
// constructor() { }
// getData() { }
// }
// let h: any = new HttpClient()
// console.log(h.apiUrl);
// h.run()
// 2.装饰器工厂
function logClass(params: string) {
console.log(params);//山竹
return function (target: any) {
console.log(target);//类
target.prototype.name = params
}
}
@logClass('山竹')
class HttpClient {
constructor() {
}
getData() {
}
}
let h: any = new HttpClient()
console.log(h.name);
/**
* 下面是一个重载构造函数的例子.
*
* 类装饰器表达式会在运行时当做函数被调用,类的构造函数作为其唯一的参数
*
* 如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明
*/
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);
}
}
let http = new HttpClient()
http.getData()
2.属性装饰器
/**
* 属性装饰器
* 属性装饰器表达式会在运行时当做函数被调用,传入下列2个参数:
* 1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象.
* 2.成员的名字
*/
// 类的装饰器
function logClass(target: any) {
console.log(target, 1);
}
// 属性的装饰器
function logProperty(params: any) {
return function (target: any, attr: any) {
console.log(target, 2);
console.log(attr, 3);//属性名
target[attr] = params
}
}
// 属性装饰器
@logClass
class HttpClient {
@logProperty('http://shanzhu.com')
public apiUrl: string | undefined;
constructor() {
}
getData() {
console.log(this.apiUrl, 4);
}
}
let http = new HttpClient()
http.getData()
3.方法装饰器
/**
* 方法装饰器
* 它会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义.
*
* 方法装饰会在运行时传入下列参数:
* 1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象.
* 2.成员的名字
* 3.成员的属性描述符
*/
// 方法装饰器一
// function get(params: any) {
// return function (target: any, methodName: any, desc: any) {
// console.log(target);
// console.log(methodName);
// console.log(desc);
// target.apiUrl = 'xxx'
// target.run = () => {
// console.log('run');
// }
// }
// }
// class HttpClient {
// public url: any | undefined;
// constructor() { }
// @get('http://www')
// getData() {
// console.log(this.url);
// }
// }
// let h: any = new HttpClient()
// console.log(h.apiUrl)
// h.run()
// 方法装饰器二
function get(params: any) {
return function (target: any, methodName: any, desc: any) {
console.log(target);
console.log(methodName);
console.log(desc);
// 修改装饰器的方法,把装饰器方法里面传入的所有参数改为string类型
// 1.保存当前的方法
let oMethod = desc.value
desc.value = function (...args: any[]) {
args = args.map((value) => {
return String(value)
})
oMethod.apply(this, args)
}
}
}
class HttpClient {
public url: any | undefined;
constructor() {
}
@get('http://www')
getData(...args: any[]) {
console.log(args);
console.log('我是getData里面的方法');
}
}
let http = new HttpClient();
http.getData(123, 'xxx')