什么是TypeScript
typescript是拥有类型的javaScript超集, 它可以编译成普通\干净\完整的js代码 ES3
js所拥有的内容ts都支持, 并且js有es678... ts也都支持这些语法
ts拥有独特的一些数据类型 枚举 元组 void any
vueCli babel=>.ts .vue文件 转换成 普通的html和js和css
js css html
TS中声明变量
在ts中声明变量 需要使用类型注解的形式
语法 var/let/const 变量名: 数据类型 = 值
var num :Number =100
console.log(num) //100
//此时num只能为number类型 如果改为其他类型会报错
TS中的数据类型
number类型
let num: number = 123;
num = 100;
num = 100.0001;
// num = "100";
let decLiteral: number = 6;//10进制
let binaryLiteral: number = 0b1010;//2进制
let hexLiteral: number = 0xf00d;//16进制
let octalLiteral: number = 0o744;//8进制
boolean类型
//布尔类型只有两个值 true和false
let flag: boolean = true;
flag = false;
flag = 1>0;
string类型
let msg: string = "hello world";
let name: string = "你好";
let age: number = 18
msg = `${name}+年龄:${age}`
export {}
null和undefined类型
//js中null和undefined是两个基本数据类型
//在ts中 null和undefined他们是类型 也是值
var n = null;
var u = undefined;
n = null;
n = undefined;
// u=undefined
symbol类型
var _a;
var name1 = Symbol("name");
var name2 = Symbol("name");
var obj = (_a = {},
_a[name1] = "hello world",
_a[name2] = "你好世界",
_a);
array类型
//在数组中应该存放相同类型的数据
let arr: Array<string> = []; //第一种写法 react.jsx <div></div>
let arr2: string[] = []; //第二种写法
let arr3 = ["xxx",18, true];
arr.push("你好世界");
// arr.push(1234);
//在数组中最好放相同数据类型的内容
arr.forEach(item=>{
})
object类型
const obj = {
name: "你好世界",
age: 18
}
console.log(obj.name)
any类型
//msg这个数据的数据类型可以是任何的数据(和原来的js就完全一样了)
let msg: any = "1234";
msg = 123;
msg = true;
msg = [];
msg = null;
unknown类型
function fn1(){
return "这是一个字符串"
}
function fn2(){
return 1234
}
//unknown类型 只能赋值给any和unknown类型的变量
//any类型 可以赋值给任意类型的变量
let flag = true;
let res: unknown;
if(flag){
res = fn1();
}else {
res = fn2();
}
let msg:unknown = res;
console.log(res)
void类型
//void 当前方法没有返回值
function fn(num:number, num2:number): number{
return num+num2
}
function fn2(num:number, num2:number): void{
console.log(num+num2)
}
let run = fn2(1,2)
never类型
//never表示永远都不会发生值的类型
function fn(): never{
throw new Error("手动错误")
}
function fn1(): never{
while (true){
console.log(1)
}
}
function checkType(msg: string | number | boolean){
let str = "";
switch (typeof msg){
case "string":
str = "string"
break;
case "number":
str = "number"
break;
case "boolean":
str = "boolean"
break;
default:
let check: never = msg;
}
return msg+","+str
}
checkType("123")
checkType(123)
checkType(true)
tuple类型
//tuple元组: 多种元素的组合
//1.数组
//数组中的数据类型应该保持统一
// let arr: any[] = ["name", 18, true]
// arr[0].length;
// arr[1].length;
//如果不统一,那么应该尝试使用对象替代
/*let obj = {
name: "name",
age: 18,
n: true
}*/
//2.元组 必须要赋值
let arr: [string, number, boolean] = ["name", 18, true]
arr[0].length;
// arr[1].length;
//应用场景
function createState(state: any) {
let curState = state;
let setState = (newValue: any) => {
curState = newValue
}
let arr: [any, (newValue: any) =>void] = [curState, setState]
return arr
}
let [curState, setState] = createState(100);
setState(101);
console.log(curState)
let [title, setTitle] = createState("abc")
setTitle("aaa")
console.log(title)
//优化
function createState2<T>(state: T) {
let curState = state;
let setState = (newValue: T) => {
curState = newValue
}
let arr: [T, (newValue: T) =>void] = [curState, setState]
return arr
}
let [flag, setFlag] = createState(true)
setTitle(false)
console.log(title)
export {}
enum类型
//枚举类型
//就是将一组可能出现的值, 一个一个列举出来, 定义在一个类型中,这个类型就是枚举类型
//枚举类型放常量 字符串 数字 (全大写)
enum Direction {
LEFT = "LEFT",
RIGHT = "11",
TOP = "1111",
BOTTOM = 100
}
enum Url {
DEV_URL = "www.baidu.com",
PROD_URL = "www.baidu.com1",
TEST_URL = "www.baidu.com2"
}
let a:Direction = Direction.LEFT;
function move(direction: Direction){
console.log(direction)
switch (direction){
case Direction.LEFT:
console.log("向左移动")
break;
case Direction.RIGHT:
console.log("向右移动")
break;
case Direction.TOP:
console.log("向上移动")
break;
case Direction.BOTTOM:
console.log("向下移动")
break;
default:
let err:never = direction
}
}
move(Direction.LEFT)
move(Direction.RIGHT)
move(Direction.TOP)
move(Direction.BOTTOM)
// move(null)
TS中的函数
函数类型
//js中 函数 function是一等公民
/*
type Fn = (qwerty)=>void
let fn:Fn = function (){
return "aaaa"
}
let fn2: Function = (a:string)=>{
return a
}*/
/*type Fn = (number, number) => void;
let fn:Fn = function (a: number, b: number){
}*/
函数的参数类型和返回值
//函数的参数类型 可以按照普通数据类型加注解的方法去直接写 num1:number, num2:number
//函数的返回值 注解 () :number=>{} 如果没有返回值 类型用void
//在开发过程中,一般不用去写函数返回值的类型注解(自动推导)
function sum(num1:number, num2:number){
return num1 + num2
}
sum(1,2);
//箭头函数或者匿名函数
//item可以根据上下文环境推导出来, 这个时候可以不去添加类型注解
let arr = ["a","b","c"];
// let arr = [1,2,3,4,5];
arr.forEach(function (item){
item.toUpperCase()
})
//函数中的参数是对象的时候
//data => 对象
//data: {name:string, age:number, flag?:boolean} //加问号表示可以传递也可以不传递\
//属性之间可以使用,号或者;来分割
//每个属性的类型也是可以指定的 ,如果不指定那么就是any类型
function sentData(data: {name:string, age:number, flag?:boolean}){
console.log(data.name)
console.log(data.age)
console.log(data.flag)
}
sentData({name:"1",age:2, flag:true})
sentData({name:"1",age:2})
函数中的默认参数
//参数默认值 js中也可以这么写
function fn(x:number, y:number=100){
return x+y
}
fn(100,200); //300
fn(100); //200
//默认参数是第一个
//一般情况下,我们会把拥有默认值的参数放到方法的最后一个 这样便于后续处理
function fn2(num:number = 100, y:number){
return num+y
}
fn2(undefined,200)
fn2(null,200)
/*
function fn(x:number, y?:number=100){
return x+y
}
fn(100,200); //300*/
函数中的剩余参数
//ES5中的剩余参数
/*function fn(){
console.log(arguments)
}*/
//ES6中展开运算符
function fn(...nums:number[]){
console.log(nums)
}
fn(1,2,3,4,5)
可推导的this类型
//01_可推导的this类型
//ts在编译时,认为我们的this是可以正确去使用的:
// ts认为sayHello函数有一个对应this的外部对象(obj),所以在使用是,就会把this当作该对象
let obj = {
name: "你好世界",
sayHello(){
console.log(this.name)
}
// sayHello: function(){
// console.log(this.name)
// }
};
obj.sayHello()
不确定的this类型
function sayHello() {
console.log(this.name)
}
sayHello();//==>this ==>window
let obj = {
name: "你好世界",
sayHello
};
obj.sayHello();//==>this ==>obj
//原因
//首先我们使用ts来编写代码 主要就是为了检测类型使我们的代码更加的安全
指定的this类型
type Obj = {
name: string
}
//this:Obj ==>只是为了告诉ts当前的this是谁,并不是当前方法的第一个参数,他在执行的时候是被忽略的
function sayHello(this:Obj, a) {
console.log(this.name, a)
}
let obj = {
name: "你好世界",
sayHello
};
obj.sayHello(123);//==>this ==>obj
函数的重载
//函数签名 通过函数签名的形式来实现函数重载
function sum(a1:number, a2:number): number;
function sum(a1:string, a2:string): string;
function sum(a1: any, a2: any){
return a1+a2
}
//在调用sum函数的时候,它会根据我们传入的参数类型,来决定执行函数时,到底执行哪一个函数签名
sum(1,2);//3
sum("1","2");//"12"
//有重载的情况下,那么哪怕数据类型是any只要不符合任意一个重载函数签名,那么都是不能使用的
// sum({a1:1},{a2:2});//"12"
//需求: 定义一个函数,可以传入字符串或者数组, 要求获取他们的长度
//通过联合类型来去实现效果
/*function getLength(arg: string|any[]){
return arg.length
}*/
//通过函数重载来实现效果
function getLength(arg: string): number;
function getLength(arg: any[]): number;
function getLength(arg: any){
return arg.length
}
getLength("wertyuio");
getLength([1,2,3,4,5]);
//在可能的情况下,尽量来选择通过联合类型去实现
TS中的接口
接口的声明
//之前我们通过type用来声明一个对象类型
/*type Person = {
name: string,
age: number
}*/
//对象类型的声明还有另外一种方式
interface Person {
name: string,
age: number
}
let obj:Person={
name:"你好世界",
age: 2021
}
export {}
interface可选属性
interface Person {
name: string,
friend?: {
name: string,
age?: number,
girlFriend?: {
name: string
}
}
}
let obj: Person = {
name: "哈哈",
friend: {
name: "xixi"
}
}
console.log(obj.name)
console.log(obj.friend?.name)
console.log(obj.friend?.girlFriend?.name)
interface的只读属性
//只读属性,在初始化完毕之后是无法重新赋值的
interface Person {
readonly name: string,
readonly friend?: {
name: string,
age?: number,
girlFriend?: {
name: string
}
}
}
let obj: Person = {
name: "哈哈",
friend: {
name: "xixi"
}
}
//Cannot assign to 'name' because it is a read-only property
// obj.name = "xxx"
// obj.friend = {}
// obj.friend.name = "xxx"
console.log(obj.name)
console.log(obj.friend?.name)
console.log(obj.friend?.girlFriend?.name)
interface的索引类型
interface Obj {
[name:number]: string
}
let obj:Obj = {
0: "0",
1: "a",
2: "b",
3: "c",
4: "d"
}
interface Obj1 {
[name:string]: number
angular:number,
}
let obj2:Obj1 = {
"html": 0,
"css": 1,
"js": 2,
"Vue": 3,
"ts": 4,
"angular": 5
}
interfce的函数类型
// type Fn = (num:number)=>void
interface IFn {
(num1:number, num2:number):number
}
let fn:IFn = (num1,num2)=>{
return num1+num2
}
//一般情况下 我们还是推荐大家来使用类型别名(type)来定义函数
interface的继承
interface Obj {
name: string,
run: () => void
}
interface Obj2 {
age: number
}
//接口是支持多继承的(类的继承只能继承一个)
interface Obj12 extends Obj, Obj2 {
jump: () => void
}
let obj: Obj12 = {
name: "你好",
age: 18,
run(){},
jump(){}
}
interface和type的区别
//我们发现interface和type都可以用来定义类型, 那么在开发过程中,到底应该选择哪个
//1. 如果定义的是对象类型,那么通常推荐使用interface
//2. 如果定义的是非对象 function Direction 推荐使用type
//interface和type之间有什么异同
//1.interface可以重复声明 type不能重复声明
//2.type定义的别名, 别名是不能重复
/*type Person = {
name: string,
run:()=>void
}
type Person = {
age: number
}*/
interface Person {
name: string,
run:()=>void
}
interface Person {
age: number
}
let obj: Person = {
name: "aa",
run(){},
age: 18
}
/*let img = document.getElementById("img") as HTMLImageElement
let div = document.getElementById("div") as HTMLDivElement
window.navigator.userAgent //==>当前浏览器信息
interface Window{
helloWorld: string
}
window.helloWorld = "你好世界"*/
interface字面量赋值
interface Person{
name: string,
age: number
}
let obj = {
name: "你好",
age: 18,
flag: true
}
let p:Person = obj;
//在ts通过字面量直接赋值的过程中, 为了进行类型推导会进行严格的类型限制
//但是我们之后讲一个 变量 赋值给其他变量的时候, ts会进行一个(freshness)擦除操作
console.log(p);
function fn(a:Person){
}
TS中的类
ts中类的定义
class Person{
name!:string;
age:number;
constructor(name:string, age:number) {
this.name = name;
this.age = age;
}
running(){
console.log(this.name + " running")
}
eating(){
console.log(this.name + " eating")
}
}
let p = new Person("ES6+",7)
p.running()
p.eating()
console.log();
/*p2={
name: "ES6+",
age: 7
}*/
ts中类的类型
class A{
name!:string;
age:number;
constructor(name:string, age:number) {
this.name = name;
this.age = age;
}
running(){
console.log(this.name + " running")
}
eating(){
console.log(this.name + " eating")
}
}
let p: A = new A("ES6+",7);
p.running()
p.eating()
/*p={
name: "ES6+",
age: 7
}*/
let p2: A = {
name:"p2",
age: 18,
running(){},
eating(){}
}
console.log();
export {}
ts中类的继承
class Person{
name!:string;
age:number;
constructor(name:string, age:number) {
this.name = name;
this.age = age;
}
running(){
console.log(this.name + " running")
}
eating(){
console.log(this.name + " eating")
}
}
class A{}
//Classes can only extend a single class.
// class Student extends Person, A{
class Student extends Person{
learn: string;
constructor(name:string, age:number, learn: string) {
super(name, age);
this.learn = learn
}
running(){
//this ==> s
//super===> Person
super.running()
console.log(this.name + " Student running")
}
}
let s: Student = new Student("学生", 20, "TypeScript");
s.running();
s.eating();
console.log(s)
ts中类的成员修饰符
//在typeScript中 类的属性和方法支持三种修饰符
//1 public
// 修饰的是在任何地方可见 公有的属性或方法 默认编写的属性就是public的
//2 private
// 修饰的是仅在同一类中可见 私有的属性或方法(不参与继承)
//3 protected
// 修饰的是仅在类自身及子类中可见 受保护的属性或方法(不能读写)
/*
class Person{
public name!:string;
public age:number;
constructor(name:string, age:number) {
this.name = name;
this.age = age;
}
running(){
console.log(this.name + " running")
}
eating(){
console.log(this.name + " eating")
}
}
class Student extends Person{
public learn: string;
constructor(name:string, age:number, learn: string) {
super(name, age);
this.learn = learn
}
running(){
//this ==> s
//super===> Person
super.running()
console.log(this.name + " Student running")
}
}
let s: Student = new Student("学生", 20, "TypeScript");
s.running();
s.eating();
console.log(s)*/
//private 修饰
/*
class Person{
private name:string;
constructor(name:string) {
this.name = name;
}
}
let p = new Person("aa");
console.log("=======>",p)
*/
//protected 修饰
class Person{
protected name:string;
constructor(name:string) {
this.name = name;
}
}
let p = new Person("aa");
// console.log("=======>",p.name)
/*
p.running()
class Student extends Person{
constructor(name:string) {
super(name);
}
running(){
console.log(this.name + " Student running")
}
}*/
ts中类的getters和setters.
//在一些时候,我们不希望直接去修改类中的私有属性,或者我们想去监听当前这个属性被读写的过程,这个时候我们可以使用存取器
var Person = /** @class */ (function () {
function Person(name) {
this._name = name;
}
Object.defineProperty(Person.prototype, "name", {
get: function () {
console.log("get name 被触发");
return this._name;
},
set: function (newValue) {
console.log("set name 被触发");
this._name = newValue;
},
enumerable: false,
configurable: true
});
return Person;
}());
var p = new Person("aa");
console.log("=======>", p.name);
p.name = "1111";
ts中类的静态成员
//类 的静态成员
//之前我们在类中定义的属性和方法都属于是通过实例才能访问或者使用的(对象级别)
//有时候我们也需要定义类级别的属性和方法
//在ts中通过关键字static来定义
class A{
//静态属性 使用static来修饰
static state: string = "初始化的值"
time: string = "初始值"
constructor() {
this.time = "2021-11-11";
}
//静态方法
static getState(){
return A.state
}
helloWorld(){
console.log("你好世界")
}
}
//访问的是类的静态属性
A.state = "a"
//访问的是类的静态方法
A.getState()
//实例的访问
let a = new A();
console.log(a.time);
a.helloWorld();
ts中的抽象类
//多态 => 编译多态 运行多态
//编译多态=>指为不同数据类型的实体提供统一的接口(把相关的数据整合起来通过同一个接口去调用)
//运行多态=>重载和重写
//继承是多态(编译多态)使用的前提
//在定义很多通用的接口时,通常会让调用者传入父类, 通过多态来实现更加灵活的调用方式
//但是,父类本身其实并不需要对某些方法进行具体的实现,所以父类中定义的方法,可以定义为抽象方法
//抽象方法=>
//在ts中没有具体实现的方法(抽象方法)
//抽象方法, 必须存在于抽象类中
//抽象类必须使用 abstract声明
//抽象类=>
//抽象类是不能被实例化的(也就是不能通过new关键字来创建);
//抽象方法必须被子类实现, 否则该类必须是一个抽象类
//抽象类 abstract
abstract class Shape{//形状类
//抽象方法
abstract getArea():number
}
class Rectangle extends Shape{//矩形类
public width: number
public height: number
constructor(width: number, height: number) {
super()
this.width = width
this.height = height
}
getArea(){
return this.width * this.height
}
}
let rectangle = new Rectangle(100,100);
class Circle extends Shape{//圆形类
public r: number
constructor(r: number) {
super()
this.r = r
}
getArea(){
return this.r * this.r * 3.14
}
}
let circle = new Circle(100);
function getArea(shape:Shape){//获取面积
console.log(shape.getArea())
}
getArea(rectangle)// width height
getArea(circle)// R
//抽象类 不能使用new创建 不能被实例化
// let shape = new Shape()
// getArea(shape)//shape => {getArea(){}
|