TypeScript

一、TS开发环境搭建

1、安装编译TS的工具包

问题:为什么要安装编译TS的工具包?

答:Node.js/浏览器,只认识JS代码,不认识TS 代码。需要先将TS 代码转化为J5 代码,然后才能运行。

安装命令:

#安装命令

npm i -g typescript

#检查是否安装成功(查看typescript的版本) 

tsc -v                                        

2、编写,编译,并运行TS代码

编写:在vscode中创建一个hello.ts的文件:内容如下:

console.log("你好TS");
const age: number = 18;
console.log(age);

编译并运行:

第一种:在vscode终端中执行如下代码(会在同级目录下生成一个同名JS文件):

#将hello.ts这个TS文件编译成一个JS文件(编译成功后会在这个TS同级目录中生成一个同名的hello.js文件)
tsc hello.ts

#执行js文件
node hello.js //会在页面输出:你好TS 和 18

第二种:在vscode终端中执行如下代码(不会在同级目录下生成一个同名JS文件):   

因为第一种每次修改代码后,都要重复执行两个命令,才能运行TS代码,太繁琐  

简化方式:使用ts-node包,直接在 Node.js 中执行TS 代码。  

安装命令:

npm i -g ts-node (ts-node包提供了ts-node 命令)

编译并运行:

ts-node hello.ts //解释:ts-node 命令在内部偷偷的将TS->JS,然后,再运行JS代码。会在页面输出:你好TS 和 18  (不会生成一个同名的JS文件了)

                                                                                                                                                           

二、常用基础类型

可以将 TS 中的常用基础类型分为两类

1.JavaScript 已有类型

  • 原始类型: number /string /boolean /null /undefined /symbol
  • 对象类型:object(数组、对象、函数等)

2. TypeScript 新增类型

  • 联合类型、自定义类型(类型别名)、接口、元祖、字面量类型、枚举、void、any 等

三、TS中的类型声明

1、原始类型的声明

//数值类型
let count = 20; //当一个变量申明并且直接赋值后,可以不指明它的类型,因为TS可以自己做类型推断,推断出这个count是number类型
let height: number;//当声明一个变量后,没有直接赋值,建议指明它的类型
let age: number = 10;
let weight: number = 75.6;

//字符串类型
let myname: string = "张三";

//布尔类型
let isOk: boolean = false;

//null类型
let snull: null = null; 

//undefined类型声明
let undefin: undefined = undefined;

//可以把undefined赋值给void类型,但是没有任何意义
let unusable: void = undefined;

//数组:第一种写法
let arr1: number[] = [1, 2, 3];
//数组:第二 种写法
let arr2: Array<number> = [1, 2, 4];
let arr3: Array<string> = ["a", "b", "c"];

2、TS新增类型的声明

元组 | any

//元组:元组类型表示允许一个已知元素数量和类型的数组,各个元素的类型可以不相同,也可以相同。
let arr: [number, number, string, boolean] = [1, 2, "abc", true];

//any:任意类型,可以表示为任意类型,未标注类型时默认为此类型。
let temp: any; 
temp = 123;
temp = false;
temp = "abc";

枚举

//枚举:用enum关键字来声明枚举,枚举成员是有值的,默认为从0开始自增的数值,
// 我们把枚举成员的值为数字的枚举称为:数字枚举
enum Direction1 {
  Up, //Up的默认为从0开始自增的数值,所以它的值默认为0 它相当于Up=0
  Down, //它相当于Down=1
  Left, //它相当于Left=2
  Right, //它相当于Right=3
}
//用法:
console.log(Direction1.Up); //输出:0

enum Direction2 {
  Up = 2, //Up的默认为从0开始自增的数值,但是此处我们已经指定了它的值为2
  Down, //它相当于Down=3
  Left, //它相当于Left=4
  Right, //它相当于Right=5
}

enum Direction3 {
  Up = 2, //我们也可以手动指定枚举的值
  Down = 4,
  Left = 6,
  Right = 8,
}

//字符串枚举:枚举成员的值为字符串的时候此枚举为字符串枚举,
//字符串枚举没有自增长的行为,因此字符串枚举的每个成员必须要有初始值
enum Direction4 {
  Up = "上",
  Down = "下",
  Left = "左",
  Right = "右",
}
//用法:
console.log(Direction4.Up); //输出:上

//案例:用法
function changeDirection(direction: Direction4): void {
  console.log(direction);
}
changeDirection(Direction4.Down) //输出:下

枚举的原理:

字面量类型

let str1 = "Hello TS";   //str1的类型为:string
const str2 = "Hello TS"; //str2的类型为:"Hello TS"

let str1: 18 = 18; //当把str1的类型指定为数值类型的18后,那么它的值就只能为18了,不能为19或者其他,它相当于const str1 = 18;
let str2: "中国" = "中国"; //当把str2的类型指定为字符串类型的"中国"后,那么它的值就只能为"中国"不能为其他的值了,它相当于const str2 = "中国";
let str3: true = true; //当把str3的类型指定为布尔类型的true后,那么它的值就只能为true,不能为false ,它相当于const str32: true = true;

字面量类型的用处:

使用模式:字面量类型一般配合联合类型一起使用。

使用场景:一般用来表示一组明确的可选值列表

比如:在贪吃蛇游戏中,游戏的方向的可选值只能是上,下,左,右中的任意一个值(它的用处和枚举很类似)

function changeDirection(direction: "上" | "下" | "左" | "右") {
  console.log("您按了" + direction);
}
changeDirection("上") //输出:您按了上

相比string类型,字面量类型更加精确,严谨 ,不给你传错值的机会,固定死了你可以传那些值。

3、类型别名

使用type关键字创建类型别名                  

//类型别名: 类型别名其实就是自己先定义好一个类型,后续有其他变量要使用这个类型的时候,直接用了,避免每次写重复的类型代码:
type CustomArry = (string | number | boolean)[];
let arr1: CustomArry = [1, 2, "a"];
let arr2: CustomArry = ["a", "b", "c", 1, 2, 3, false];
//类型别名的作用是当存在多个变量使用同一个类型的时候,避免每次都写重复很长的数据类型 如:(string | number | boolean)[] 
// let arr1: (string | number | boolean)[] = [1, 2, "a"];
// let arr2: (string | number | boolean)[] = ["a", "b", "c", 1, 2, 3, false];

//用type关键字定义一个Person类型别名
type Person = {
  name: string;
  age: number;
  [key: string]: any; // 任意属性:即这个key可以是任意值的字符串
};

//用法
let user: Person = {
  name: "Alice",
  age: 25,
  job: "Engineer",
};

4、对象类型

1、Object,object对象

//Object:大Object 代表所有拥有 toString、hasOwnProperty 方法的类型
//所以所有原始类型、非原始类型都可以赋给 Object(严格模式下 null 和 undefined 不可以)
let obj1: Object = {};
let obj2: Object | null = null; //联合类型:表是obj2既可以是object类型也能是null类型

let obj3: Object;
obj3 = 1; // 编译正确
obj3 = "a"; // 编译正确
obj3 = true;  // 编译正确
obj3 = {};  //编译正确
//obj3 = null;  // 报错
//obj3 = undefined; // 报错

//object:小object 类型用于表示所有的非原始类型,即我们不能把 number、string、boolean、symbol等 原始类型赋值给 object。
//在严格模式下,null 和 undefined 类型也不能赋给 object。
let obj4: object;
obj4 = {}; // 编译正确
//obj4 = 1; // 报错
//obj4 = "a"; // 报错
//obj4 = true; // 报错
//obj4 = null; // 报错
//obj4 = undefined; // 报错

2、自定义对象

在 TypeScript 中,对象是非常灵活的数据结构,你可以使用它们来组织和管理你的应用程序中的数据和行为。通过使用类、接口、类型别名和工厂函数,你可以创建出结构清晰、易于维护的代码。

//1、声明一个kitty的空对象: 此处的{}表示对象。而对象中没有属性或方法时,称为:空对象。
let kitty = {};

//2、声明一个person对象,对象包含了两个属性name和age,两个方法sayHello和myInfo
let person: {
  name: string;
  age: number;
  sayHello(): void; //没有返回值的方法
  myInfo(msg: string): string; //返回值为string类型的方法
};
person = {
  //给person对象赋值
  name: "张三",
  age: 18,
  sayHello() {
    console.log(`我叫${this.name},我会唱歌`);
  },
  myInfo(msg: string) {
    return `我叫${this.name},我今年${this.age}岁,我会${msg}`;
  },
};
//用法:
person.sayHello(); //输出:我叫张三,我会唱歌
console.log(person.myInfo("跳舞")); //输出:我叫张三,我今年18岁,我会跳舞

//3、对象定义方式一:使用对象字面量语法直接创建一个user 对象,并赋值
let user = {
  name: "张三",
  age: 18,
  gender: "男",
  speak: function () {
    console.log(`Hi, my name is ${this.name}.`);
  },
};

//4、使用工厂函数创建对象
//先用type关键字来定义一个对象类型
type PersonType = {  
  firstName: string;
  lastName?: string;
  greet: () => string;
};
//利用工厂函数返回一个对象,它可以用于封装对象的创建逻辑
function createPerson(firstName: string, lastName: string): PersonType {
  return {
      firstName,
      lastName,
      greet() {
          return `你好,我叫 ${this.firstName} ${this.lastName}`;
      }
  };
}
//用法
let myperson = createPerson("张","三");
console.log(myperson.greet()); // 输出 "你好,我叫张三"


//5、对象定义方式:构造函数+原型方法
function Users(this: any, name: string, age: number, gender: string): void {
  //为什么要在参数中加this:any,如果不加这一句就会报TS2683错误
  this.name = name;
  this.age = age;
  this.gender = gender;
}
Users.prototype.speak = function () { //给Users对象扩展一个speak方法
  console.log(`Hi, my name is ${this.name as any}.`);
};
let myuser = new (Users as any)("张三", 18, "男"); //为什么要写成:new (Users as any)("张三", 18, "男");?为什么不直接写成:new Users("张三", 18, "男"); 如果不这样写会报:TS7009错误
myuser.speak();

3、TS中的类型运算符:typeof

let str = "Hello TS";
console.log(typeof str);

//根据已有变量的值,获取该类型
let p = { x: 1, y: 2 };
function formatPoint(point: typeof p) {
  //根据typeof关键字来获取p的类型。point的类型就是p的类型
  console.log(point.x);
  console.log(point.y);
}
//用法:
formatPoint(p); //输出:1 2
formatPoint({ x: 3, y: 4 }); //输出:3 4

四、函数

1、普通函数

//函数声明的方式:定义一个名称为add的函数:带两个类型为number类型的参数,返回值为string类型
function add(num1: number, num2: number): string {
  return (num1 + num2).toString();
}
//函数表达式的方式:定义一个名称为add的函数:带两个类型为number类型的参数,返回值为string类型
const add2: (num1: number, num2: number) => string = (num1, num2) => {
  return (num1 + num2).toString();
};

//函数声明的方式:定义一个名称为message的函数,带一个类型为string的msg参数,没有返回值(void)
function message(msg: string): void {
  console.log(`您收到最新消息:${msg}`);
}
//函数声明的方式:定义一个名称为getName的函数,带两个类型为string类型的参数,其中参数lastName可传可不传,返回值为string类型
function getName(firstName: string, lastName?: string): string {
  if (lastName == undefined) {
    return firstName;
  }
  return firstName + lastName;
}

//函数声明的方式:定义一个名称为axiosRequest的函数,带一个名称为config的参数,参数类型是一个对象{ url: string; method?: string },对象的method属性可传可不传
function axiosRequest(config: { url: string; method?: string }): void {
  console.log("发起异步请求")
}

2、泛型函数

//声明一个名称为getVal的泛型函数,函数参数arg为T类型,函数的返回值为T类型
function getVal<T>(arg: T): T {
  return arg;
}
let age: number = getVal<number>(18);
console.log(age); //输出 18

let myname: string = getVal<string>("张三");
console.log(myname); //输出 张三

五、接口           

接口声明后,直接使用接口名称作为对象的类型
当一个对象类型被多次使用时, ,一般使用接口(interface)来描述对象的类型,达到复用的目的

接口只能给对象指定类型

接口声明后,直接使用接口名称作为对象的类型

//定义一个名称为IAnimal接口
interface IAnimal {
  name: string;
}
//定义一个名称IKitty的接口,它继承了IAnimal接口 (extends关键字用于接口的继承。表示IKitty继承IAnimal。那么此时IKitty中除了有自己定义的ability属性外,还多了一个从IAnimal接口中继承来的name属性)
interface IKitty extends IAnimal {
  ability: string;
}
//用法:声明一个名称为mykitty的对象,并指明了它是Kitty类型(这里的接口IKitty就是用来给对象mykitty指定类型的)
let mykitty: IKitty = { name: "小猫", ability: "爬树" };

接口与类型别名的区别

相同点:接口与类型别名都可以为对象指定类型

不同点:接口只能给对象指定类型,但是类型别名可以给任意类型指定别名

例如:

//类型别名可以为任意类型指定类型,而在这里接口则不行,接口只能为对象指定类型
type Animal = number | string;
let kitty1: Animal = 14;
let kitty2: Animal = "14";

六、类

类的基本使用:

class Person {
  name = "张三"; //直接赋值了,TS可以自动类型推断出name是string类型,相当于:name:string="张三"
  age: number; //因为age没有赋初始值,所以建议给它指定类型,否则它的类型就是any类型

  //TS中用constructor关键字作为类的构造函数,构造函数是没有返回值的,所以不能指定返回类型
  //类可以有构造函数,也可以不用构造函数
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  //类中的方法
  hello(spe: string) {
    console.log(`大家好,我叫${this.name},我今年${this.age}岁,我会${spe}`)
  }
}

//用法:
const p = new Person("李四", 18);
p.hello("唱歌"); //输出:大家好,我叫李四,我今年18岁,我会唱歌

类的继承

                                                                                                                                                                                                                                                                                                                                                                                                                                 

                                                                                                                                                                                                                                                              

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值