|
一、介绍
1.typescript是由微软开发的一款开源的编程语言
2.ts是js的超级,拓展了js语法,更像java/c#这样面向对象语言,更适合开发大型项目。
3.谷歌也在大力支持ts,谷歌的angular2x+ 就是基于ts语法的。
4.最新的Vue ,React 也可以集成ts。
二、安装和编译
1.安装:npm install -g typescript
2.生成配置文件:tsc --init 创建tsconfig.json 文件(eg:可修改输出地址“outDir”:“./js”,等配置)
3.编译:tsc hello.ts (hello.ts 是自己建的ts名)
4.点击菜单栏 任务-运行任务 点击tsc 监视-tsconfig.json ,然后就可以自动生成代码了。
三、ts的数据类型
1.布尔类型(boolean)
2.数字类型(number)
3.字符串类型(string)
4.数组类型(array)
5.元祖类型(tuple)
6.枚举类型(enum)
7.任意类型(any)
8.null 和 undfined
9.void 类型
10.never类型
四、各类型的用法
1.布尔类型(boolean)
let flag:boolean = true;
flag =false;
2.数字类型(number)
3.字符串类型(string)
let str:string = '';
str = 'I am string';
4.数组类型(array)
let arr:string[]=[];
arr = ['1','2','3','4']; or let arr:Array<number> =[1,2,3,4];
5.元祖类型(tuple)
//已知数组元素的个数,并且知道每个元素的类型 let tupleArr :[string,number] =['lalala',2];
6.枚举类型(enum)
enum Color{
red = 1,
blue,
orange = 5,
green = 7
}
let redNum:Color = Color.red //1
let blueNum:Color = Color.blue //2
let orangeNum:Color = Color.orange //5
let red:string = Color[1] //red
let blue:string = Color[2] //blue
let orange:string = Color[5] //orange
7.任意类型(any)
let notSure:any = 4;
notSure = 'maybe a string instead';
notSure = false; //okay
8.null 和 undfined
//strictNullChecks标记的启用是在tsconfig.json文件里进行配置。
// {
// "compilerOptions": { //编译选项,可以被忽略,这时编译器会使用默认值
// "strictNullChecks": false, //在严格的null检查模式下,null和undefined值不包含在任何类型里,只允许赋值给void和本身对应的类型。
// }
// }
//"strictNullChecks": false,
//默认情况下,null 和 undefined 是其它类型的子类型,可以赋值给其它类型,如number类型,此时,赋值后的类型会变成 null 或 undefined。
let hh: number;
hh = null; //ok的
hh = undefined; //ok的
//"strictNullChecks": true,
let ss: number;
ss = null; //提示不可以
ss = undefined; //提示不可以
//定义没有赋值就是undifined; let aa :string | undifined; console.log(aa) //undefined
//一个元素可能是number,null,undifined let num: number | null | undefined num=123;
9.void 类型
//表示方法没有返回任何类型
function run(): void {
console.log(111);
}
run()
//表示传参是number类型,函数返回值也是number类型
function sum(num:number): number {
console.log(111);
return num + 123
}
sum(12);
10.never类型
//never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。 // 即使 any也不可以赋值给never。通常表现为抛出异常或无法执行到终止点(例如无线循环)。比如:
let x: never;
let y: number;
// 运行错误,数字类型不能转为 never 类型
x = 123;
// 运行正确,never 类型可以赋值给 never类型
x = (() => { throw new Error('exception') })();
// 运行正确,never 类型可以赋值给 数字类型
y = (() => { throw new Error('exception') })();
// 返回值为 never 的函数可以是抛出异常的情况
function error(message: string): never {
throw new Error(message);
}
// 返回值为 never 的函数可以是无限循环这种无法被执行到的终止点的情况
function loop(): never {
while (true) { }
}
五、类
1.类的写法
2.类的继承
3.属性修饰符(public、protected、private)
4.必传参数和可选参数
//类里面的修饰符:ts里定义属性的时候提供了三种修饰符:
/*
public:共有 在类里面、子类、类外面都可以访问
protected:保护类型 在类里面,子类里面可以访问,在类外部没法访问
private:私有 在类里面可以访问 ,类外面和子类都不访问
属性如果不加修饰符,默认是public
*/
class Person {
name: string; //必传,属性修饰符这里没写就默认是public,同public name:string;
private sex: string;
protected age?: number; //age:可有可没有
//namepro:必传,agepro:可传可不传,可选参数必须配置到 参数的最后面 //‘lisi’是namepro的默认值
constructor(namepro: string = 'lisi', sexpro: string = '男', agepro?: number) {
this.name = namepro;
this.age = agepro;
this.sex = sexpro;
}
run(): void {
console.log(this.name);
}
}
let zhangsan = new Person('zhangsan', '女');
zhangsan.run();
zhangsan.age; //提示出错。age是保护类型
class Web extends Person {
constructor(name: string) {
super(name) //继承父级的参数需要同过super函数传值
}
work() {
console.log(this.sex); //sex是父类的私有属性,所以子类是访问不到的,这里会提示错误
}
}
5.参数中的三点运算符
//三点运算符,接受新参传过来的值
function sumFn(...result: number[]): number {
let sum: number = 0;
for (let i = 0; i < result.length; i++) {
sum += result;
}
return sum;
}
sumFn(1, 2, 3, 4);
sumFn(1, 2, 3, 4, 5, 6)
//如果有默认的参数,那传参前面就是默认的参数,剩下的就在。。。的result中
function sumFn(a:number,b:number,...result: number[]): number {
let sum: number = a+b;
for (let i = 0; i < result.length; i++) {
sum += result;
}
return sum;
}
sumFn(1, 2, 3, 4);
sumFn(1, 2, 3, 4, 5, 6)
六、ts函数重载
1.ts中的重载:通过为同一个函数提供多个函数类型定义来试下多种功能的目的
function getInfo(name: string): string;
function getInfo(age: number): string;
function getInfo(str: any): any {
if (typeof str === 'string') {
return '我叫' + str;
} else {
return '我的年龄' + str;
}
}
getInfo('张三') //我叫张三
getInfo(20) //我的年龄20
七、类的静态属性 静态方法
1. /*es5中的写法*/ function Person () {
// this.run = function () {} // 实例方法
// this.run = ()=> {}
}
Person.run = function () {} // 静态方法
2./*es6的写法*/
class Person1 {
name:string;
static sex = 'man'; // 静态属性
constructor(name: string) {
this.name = name;
}
eat() {
console.log(`${this.name}吃饭`)
}
static work() {
console.log(`这是一个静态方法` + Person1.sex)
// console.log(`${this.name}哈哈`) // 错误的写法,静态方法里面无法调用类的属性、方法。
}
}
var p = new Person1('aaa');
p.eat(); // 实例方法调用
Person1.work(); // 静态方法调用
八、ts中的抽象类和抽象方法,多态
1.typescript中的抽象类是提供其它类的基类,不能直接被实例化;
2.用abstract关键字定义的抽象方法和抽象类,不包括具体实现必须在派生类实现。
3. 抽象类: abstract 修饰, 里面可以没有抽象方法。但有抽象方法(abstract method)的类必须声明为抽象类(abstract class)
4.抽象类用于定义标准
5. 多态:父类定义一个方法不去实现,让继承它的子类去实现 每一个子类有不同的表现
abstract class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
//抽象方法 ,不包含具体实现,要求子类中必须实现此方法
abstract eat(): any;
//非抽象方法,无需要求子类实现、重写
run(): void {
console.log('非抽象方法,不一定要子类实现、重写');
}
}
//子类中必须实现父类抽象方法,否则ts编译报错
class Dog extends Animal {
eat() {
return this.name + '吃鱼'
}
}
class Cat extends Animal {
//子类中必须实现父类抽象方法,否则ts编译报错
eat() {
return this.name + "吃鱼";
}
}
var dog = new Dog("tom");
var cat = new Cat("kitty");
console.log(dog.eat());
console.log(cat.eat());
//多态 ,一种事物的不同表现形态。如下面的代码中 先声明变量f是Animal类型,具体是Dog还是Cat,在new 对象时才知道
//如果是Dog,则f.eat()调用的是Dog类中的eat方法;如果是Cat,则f.eat()调用的是Cat类中的eat方法,这就是多态!!!
var f: Animal;//声明变量为Animal类型
//f=new Dog("sunny");
f = new Cat("sunny");
console.log(f.eat());
九、接口
1.接口:行为和动作的规范,对批量方法进行约束
2.接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面
3.分类:属性接口、函数类型接口、可索引接口、类类型接口
(1)属性接口:
//属性接口
interface fullName{
firstName:string;
secondName:string;
}
function getName(name:fullName):void{
console.log(name.firstName + name.secondName);
}
getName({
firstName:'Li',
secondName:'haha'
})
interface Shape {
head: string;
arm: string;
}
interface Human {
name: string;
age: number;
shape: Shape;
say(word: string): void;
}
let jack: Human = {
name: 'Jack',
age: 18,
shape: {
head: 'head',
arm: 'arm'
},
say(word: string) {
console.log(word)
}
}
jack.say('hi')
(2)函数类型接口:
//函数类型接口
interface Fn{
(key:string,val:string):string;
}
let add1:Fn = function(key:string,val:string):string{
return key+val;
}
let add2:Fn = function(key:string,val:string){
return `${key}------${val}`
}
(3)可索引接口(数组对象的约束,不常用)
//ts定义数组的方式
let arr1: number[] = [11, 22];
let arr2: Array<string> = ['11', '22'];
//可索引接口的实现
interface UserArr {
[index: number]: string
}
let arr3: UserArr = ['aa', 'bb'] //ok
console.log(arr3[0]);
let arr4:UserArr=[11,'aa'];//报错
interface UserObj{
[index:string]:string
}
let arr5:UserObj ={name:'张三'} //OK,但是这样实现已经不是数组,没有意义了,所以不常用
(4)类类型接口(对类的约束,和抽象类有点像)
interface Aniaml1 {
name: string;
eat(str: string): void;
}
//implements ,是对类Aniaml1的实现
class Dog1 implements Aniaml1 {
name: string;
constructor(name: string) {
this.name = name;
}
eat(str: string) {
console.log(this.name + '吃粮食' + str);
}
}
let d = new Dog1('小黑');
d.eat('肉');
4.接口的拓展:接口可以继承接口
interface Animal {
eat(): void;
}
interface Person extends Animal {
work(): void;
}
class Web implements Person {
name: string;
constructor(name: string) {
this.name = name;
}
eat() {
console.log(this.name + '喜欢吃馒头');
}
work() {
console.log(this.name + '写代码');
}
}
let zhangsan = new Web('zhangsan');
zhangsan.work();
十、泛型
1.泛型的定义:指在定义函数、接口或者类的时候, 不预先指定其类型,而是在使用时手动指定其类型的一种特性
2.泛型分类:泛型函数、泛型类、泛型接口
(1)泛型函数
//使用泛型函数(T:类型变量)
function myfn<T>(args: T): T {
return args;
}
let output = myfn<string>("Hello"); //明确传入类型参数
let output2 = myfn("Hello") //不传入类型参数,TS根据上下文自动推断类型
//使用泛型变量(这可以让我们把泛型变量T当做类型的一部分使用,而不是整个类型)
function myfn1<T>(args: T[]): T[] {
console.log(args.length)
return args;
}
function myfn2<T>(args: Array<T>): Array<T> {
console.log(args.length);
return args;
}
(2)泛型类
class add<T>{
value: T;
add: (x: T, y: T) => T;
}
let myTest = new add<number>();
myTest.value = 0;
myTest.add = function (x, y) {
return x + y
}
(3)泛型接口
//第一种方法
interface Test {
<T>(args: T): T
}
let myTest: Test = function <T>(args: T): T {
return args;
}
myTest<string>('20');
myTest<string>(20);
//第二种方法
interface Test1<T> {
(args: T): T
}
function myfn1<T>(args: T): T {
return args;
}
let myTest1: Test1<string> = myfn1;
myTest1('20') //ok
myTest1(20)//报错
(4)泛型约束(类型变量继承接口)
//例中,传入的参数必须具有length属性
interface Test{
length:number;
}
function myfn<T extends Test>(args:T):T{
console.log(args.length)
return args;
}
myfn(3); //error
myfn("abc") //3
十一:模块
1.模块的概念
2.模块导出的几种方式:export导出声明、export导出语句、export default、import 导入模块
3.模块封装(DB库)
4.命名空间
十二、装饰器
1.概念
2.分类:属性装饰器、方法装饰器、方法参数装饰器、类装饰器(装饰器的执行顺序也是这样)
3.装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可传参)
(1)普通装饰器
//类装饰器
function logClass(target: any) {
console.log(target); //httpClient类
params.prototype.apiUrl = '动态扩展的属性';
params.prototype.run = function () {
console.log('动态拓展的方法');
}
}
@logClass
class httpClient {
constructor() {
}
getData() {
}
}
let http: any = new httpClient();
//类装饰器重载构造函数和当前类的方法(普通装饰器)
function logClass(target: any) { //target:httpClient 类
return class extends target { //装饰器重载构造函数
apiUrl: any = '我是修改后的数据';
getData() {
this.apiUrl + '----';
console.log(this.apiUrl);
}
}
}
@logClass
class httpClient {
public apiUrl: string | undefined;
constructor() {
this.apiUrl = '我是构造函数里面的apiUrl';
}
getData() {
console.log(this.apiUrl);
}
}
let http: any = new httpClient();
console.log(http.apiUrl); //我是修改后的数据
(2)装饰器工厂(可传参)
2.1 类装饰器
//类装饰器(装饰器工厂的方式)
function logClass(params: any) { //params:传的参数
return function (target: any) {//target:httpClient类
console.log(params);//hello
console.log(target);//httpClient类
target.prototype.apiUrl = params; //可以用上传的参数
target.prototype.run = function () {
console.log('动态拓展的方法');
}
}
}
@logClass('hello') //可以传参
class httpClient {
constructor() {
}
getData() {
}
}
let http: any = new httpClient();
console.log(http.apiUrl); //hello
2.2 属性装饰器
//属性装饰器
function logProperty(params: any) { //params:传的值:我是属性装饰器
return function (target: any, attr: any) { //target:httpClient 类,attr:apiUrl
target[attr] = params;
}
}
class httpClient {
@logProperty('我是属性装饰器') //注意后面是不能加分号的
public apiUrl: string | undefined;
constructor() {
this.apiUrl = '我是构造函数里面的apiUrl';
}
getData() {
console.log(this.apiUrl);
}
}
let http: any = new httpClient();
console.log(http.apiUrl); //我是属性装饰器
2.3 方法装饰器//方法装饰器
function get(params: any) { //params:传的值:我是方法装饰器
//target:httpClient类,methodName:方法名getData, desc:方法的描述
return function (target: any, methodName: any, desc: any) {
target.addPara = '我是拓展的属性'; //同类装饰器的方法
target.addFn = function () { //同类装饰器的方法
console.log('我是拓展的方法');
}
//修改装饰器的方法,把装饰器里面传入的参数改为string类型
//获取当前的方法 desc.value =getData() {console.log(this.apiUrl);}
//先保存当前的方法
let oldMethond = desc.value;
//修改当前的方法
desc.value = function (...args: any[]) {
args = args.map((val) => {
return String(val)
})
console.log(args);//['123','xxx'] console.log(params); //我是方法装饰器
//将原来的方法继承到修改后的方法里面,这样既有修改的方法,又包含原有未修改的方法
oldMethond.apply(this, args)
}
}
}
class httpClient {
public apiUrl: string | undefined;
constructor() {
this.apiUrl = '我是构造函数里面的apiUrl';
}
@get('我是方法装饰器')
getData(...args: any[]) {
console.log(args); //['123','xxx']
console.log(this.apiUrl); //我是构造函数里面的apiUrl
}
}
let http: any = new httpClient();
http.getData;
//['123','xxx'] //我是方法装饰器 //['123','xxx']
//我是构造函数里面的apiUrl
2.4 方法参数装饰器
//方法参数装饰器:可以为类的原型增加一些元素数据(一般不用,类装饰器就可以做到这些)
function logParams(params: any) { //params:传的值:我是方法参数装饰器
//target:httpClient类,methodName:方法名getData, paramsIndex:函数参数的index索引
return function (target: any, methodName: any, paramsIndex: any) {
target.addUrl = 'params';//可以为类的原型增加一些元素数据
}
}
class httpClient {
public apiUrl: string | undefined;
constructor() {
}
getData( @logParams('我是方法参数装饰器') uuid:any) {
console.log(uuid); //haha
}
}
let http: any = new httpClient();
http.getData('haha');
来源:https://www.cnblogs.com/zhengyulu/p/12077981.html |