TypeScript快速入门笔记

一、初始TypeScript

①js的超集

        _包含js的所有元素

        _能运行js代码

        _支持ES语法

        _是一种开源、跨平台的编程语言

②编译器编译为js代码,js解析器执行

③完全兼容js代码

④静态类型检查器

_静态类型,更加严格的语法

_减少运行时异常出现的几率

_后期维护

二、第一个TypeScript程序

①安装TypeScript(看官方文档来)

npm install -g typescript  //全局安装

tsc -v  //查看版本号

②编写代码

(()=>{
    function sayHi(str:string){
        return '你好'+str
    }
    sayHi('123')
    let a:Number=30
    console.log(a)
})()

 ③手动编译为js文件(不推荐)

 终端输入: tsc 文件名

④vscode自动编译(推荐)

1.终端里:tsc --init   //生成配置文件 

2.修改配置文件 tsconfig.json :   "outDir":"./js" (导出的js文件路径) & "strict":false (是否开启严格模式)

3.启动监视任务:终端 => 运行任务=>监视tsconfig.json

三、类型声明

// 类型声明 指定ts变量(参数,形参)的类型 ts编译器,自动检查

// 类型声明给变量设置了类型,使用变量只能存储某种类型的值

①基础类型:基础类主要有 布尔类型、数字类型、字符串类型、undefined和null

_基础类型的声明如下代码所示,注意:undefined和null可以作为其它类型的子类型


// 布尔类型  boolean
let flag: boolean = true 
// flag=123 报错
flag = false

// 数字类型 number
let a:number = 10 //十进制
let a1:number = 0b1010//二进制
let a2:number=0o12 //八进制 
let a3:number=0xa //十六进制
a = 11

// 字符串类型 string
let str:string='123'
// str=123
str=''

// undefined和null, 用的不多
let u:undefined=undefined
let n:null=null
console.log(u);
console.log(n);

// u=123
// undefined和null 还可以作为其他类型的子类型
// 可以把undefined和null 赋值给其他类型的变量
let b:number=undefined
let str1:string=null
console.log(b);
console.log(str1);

②数组:

*声明方式有两种:普通声明和泛型(后面会讲)

// 定义数组一:
let arr1:number[]=[1,2,3]  
arr1=[1,2,3] 
// 定义数组二:泛型
let arr2:Array<number>=[10,20,30]

③对象

*表示非原始类型,除了number、string、boolean之外的类型

*let obj:object={}

// object 表示非原始类型,除了number、string、boolean之外的类型
let obj:object={}
// 字面量
// obj=123 报错
// obj='' 报错
obj=null
obj=undefined
obj=[]
obj=new String()
obj=String

④any(任何类型)

有优点也有缺点

// any 任何类型
let h:any=123
h=true
h="123"
h={}
h=[]
let newArr:any[]=[100,2,4,"",true]
// 有优点也有缺点
console.log(newArr[0].split(''));//数字类型没有这个方法,这里不报错,但是控制台会报错

⑤void

空值,常用于表示没有任何返回值的函数

// void空值 ,表示没有任何返回值的函数
function fun1(): void {
    console.log(123);
    // return undefined

}
console.log(fun1());
// 没有任何类型
let v: void = undefined

⑥类型推断

* ts在没有明确的指定类型的时候推测一个类型

1、定义变量的时候,直接给变量赋值,则定义类型为对应的类型

2、定义变量的时候,没有赋值,则定义类型为any类型

// ts在没有明确的指定类型的时候推测一个类型
// 2种情况:
// 1、定义变量的时候,直接给变量赋值,则定义类型为对应的类型
// 2、定义变量的时候,没有赋值,则定义类型为any类型
let t = 123;//将t定义一个number类型通过类型推断
// t=""报错
let g;
g = 123
g = ""
g = []
g = {}

⑦联合类型

* 表示取值可以为多种类型中的一种

* 只能访问此联合类型的所有类型里共有的属性或方法

* 再次赋值,走类型推断,给变量定义一个类型

// 表示取值可以为多种类型中的一种
// flag true,1 false,0 ||
let f: boolean | number | string = true
// 只能访问此联合类型的所有类型里共有的属性或方法
// f = 123 //再次赋值,走类型推断,给变量定义一个类型
f="123"
// f=true
console.log(f.toString());

四、接口

定义:它是对行为的抽象,用于对「对象的形状(Shape)」进行描述,理解为一种约束,使用interface定义

①对象类型 

1.  定义的变量比接口少了一些属性是不允许的,不能多出其他的属性

2.  ? 表示可选属性

3. readonly 定义只读属性

// 它是对行为的抽象,用于对「对象的形状(Shape)」进行描述,理解为一种约束
// 接口一般首字母大写 ,
// 定义的变量比接口少了一些属性是不允许的,不能多出其他的属性
//  ? 表示可选属性,定义对象 ? 的属性可有可无
// [propName:string]:any 任意属性和任意属性值
// [propName:string]:string 需要注意的是,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集:
// 一个接口中只能定义一个任意属性。如果接口中有多个类型的属性,则可以在任意属性中使用联合类型
// 可以用 readonly 定义只读属性
// 定义接口
interface IPerson {
    readonly id:number,
    name: string,
    age: number,
    sex?: string,
    // [propName:string]:any
    [propName: string]: string | number | boolean
}
let p: IPerson = {
    id:10,
    name: "张三",
    age: 18,
    // sex:"男",
    width: "123",//报错
}
// p.id=11

②数组类型

// 不常用,理解
interface INewArray{
    [index:number]:number//任意属性,index表示数组中的下标
}
// [1,2,3,4]  arr[0]-->obj['name']
//  0,1,2,3
let arr:INewArray=[1,2,3,4]

③函数类型

interface ISearchFunc {
    // (参数:类型,....):返回值的类型
    (a: string, b: string): boolean
}
// 参数,返回值
const fun1: ISearchFunc = function (a: string, b: string): boolean {
    return a.search(b) !== -1
}
console.log(fun1('123','1'));

五、函数

①函数声明和函数表达式

* 和js写完差不多,就是多了声明类型,还有完整写法

// //js 函数声明,命名函数
// function add(a,b){
//     return a+b
// }
// // 函数表达式,匿名函数
// let add2=function(a,b){
//     return a+b
// }

// ts 函数声明,命名函数
// a 和 b 都是number类型
// : number 表示该函数的返回值为number类型
function add(a: number, b: number): number {
    return a + b
}
console.log(add(1, 2));
let c: number = add(1, 2)
console.log(c);
// 函数表达式,匿名函数
let add2 = function (a: number, b: number): number {
    return a + b
}
console.log(add2(1,2));
// 函数完整的写法
let add3:(a:number,b:number)=>number=function(a: number, b: number): number {
    return a + b
}

②可选参数和默认参数

*   可选参数 ? 

*   默认参数 赋值

*   可选参数不能放在必选参数之前

let getName = function (x: string, y?: string, z: string = "你好"): string {
    return x + y + z
}
// 可选参数 ? 必选参数不能位于可选参数后
// console.log(getName('zhang'));
// 默认参数 是可以放在必选参数以及可选参数之后
console.log(getName('张三'));

③剩余参数和函数重载

* 剩余参数:rest参数(和es6语法)

* 函数重载:函数名相同,形参不同的多个函数

// 剩余参数
function fn(x: string, y: string, ...args: number[]) {
    console.log(x, y, args);

}
fn('', '', 1, 2, 3, 4, 5)
// 函数重载 :函数名相同,形参不同的多个函数
// 数字 相加, 字符串 拼接 ... 联合类型
// 函数重载声明,可以使用重载定义多个 newAdd 的函数类型
function newAdd(x: string, y: string): string
function newAdd(x: number, y: number): number
// 函数实现
function newAdd(x: string | number, y: string | number): string | number {
    if (typeof x == 'string' && typeof y == 'string') {
        // ...
        return x + y//字符串拼接
    } else if (typeof x == 'number' && typeof y == 'number') {
        // ...
        return x + y//数字相加
    }
}
// 这样有一个缺点,就是不能够精确的表达,
// 输入为数字的时候,输出也应该为数字,输入为字符串的时候,输出也应该为字符串
console.log(newAdd(1, 2));
console.log(newAdd('张', '三'));

④类型断言(可以手动指定一个类型)

 2种方式:

1、变量 as 类型

2、<类型>变量

//  将一个联合类型断言为其中一个类型

// Ⅰ 将任何一个类型断言为 any,any类型是访问任何属性和方法的

   Ⅱ 它极有可能掩盖了真正的类型错误,所以如果不是非常确定,就不要使用 as any 

  Ⅲ  一方面不能滥用 as any,另一方面也不要完全否定它的作用,我们需要在类型的严格性和 开发的便利性之间掌握平衡

// 将 any 断言为一个具体的类型

// 定义一个函数,获取到一个数字或者字符串的长度
// 类型断言:可以手动指定一个类型
// 2种方式
// 1、变量 as 类型
// 2、<类型>变量
// 将一个联合类型断言为其中一个类型
function getLength(x: string | number): number {
    if ((x as string).length) {
        return (<string>x).length
    } else {
        return x.toString().length
    }
}
console.log(getLength('123'));
console.log(getLength(123));
// 将任何一个类型断言为 any,any类型是访问任何属性和方法的
// 它极有可能掩盖了真正的类型错误,所以如果不是非常确定,就不要使用 as any
// 一方面不能滥用 as any,另一方面也不要完全否定它的作用,我们需要在类型的严格性和开发的便利性之间掌握平衡
(window as any).a = 10
// 将 any 断言为一个具体的类型
function abc(x: any, y: any): any {
    return x + y
}
let a = abc(1, 2) as number//a-->数值类型
let b = abc('1', '2') as string //b-->字符串类型

六、进阶

①类型别名

通过type去定义 ,用来给一个类型起个新名字

②字符串字面量类型

通过type去定义 ,用来约束取值只能是某几个字符串中的一个

// 用来约束取值只能是某几个字符串中的一个
// 张三丰,张三,张大炮
type stringType = "张三丰" | "张三" | "张大炮"
let names: stringType = "张三"

③元组Tuple

合并了不同类型的对象

let arr:number[]=[1,2,3,4]
// 数值和字符串
// 元组(Tuple)合并了不同类型的对象
let Tarr:[number,string]=[123,"123"]
// 添加内容的时候,需要是number或者string类型
Tarr.push(456)
Tarr.push("456")
// Tarr.push(true) 报错

④枚举Enum

给一组数值赋予名称

枚举类型ts代码

// 使用枚举类型给一组数值赋予名称
// 可以通过名称去拿取值,通过值去拿取名称
// 枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射
// 1,2,3,4
enum NumberType {
    one = 2,//手动赋值,没有赋值,第一个参数默认为0,后面递增加一
    two = 1,//后面的值如果没有手动赋值,会根据前面的值进行递增加一
    three,
    four
}
// 手动赋值注意:尽量不要写一些重复的值
console.log(NumberType);
// 枚举项有两种类型:常数项(constant member)和计算所得项(computed member)
// 计算所得项需要放置在已经确定赋值的枚举项之前,后面不能存放未手动赋值的枚举项
enum Color {
    red,
    blue = "blue".length,
    green = 11
}

// 常数枚举是使用 const enum 定义的枚举类型
// 常数枚举与普通枚举的区别是,它会在编译阶段被删除,并且不能包含计算成员
const enum Obj {
    o,
    b,
    j = 10 + 10
}
console.log(Obj.o);
console.log(Obj.b);
console.log(Obj.j);
// 外部枚举(Ambient Enums)是使用 declare enum 定义的枚举类型
// declare 定义的类型只会用于编译时的检查,编译结果中会被删除
// 声明文件
declare enum ABC {
    a, b, c
}
console.log(ABC.a);

js代码

// 使用枚举类型给一组数值赋予名称
// 可以通过名称去拿取值,通过值去拿取名称
// 枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射
// 1,2,3,4
var NumberType;
(function (NumberType) {
    NumberType[NumberType["one"] = 2] = "one";
    NumberType[NumberType["two"] = 1] = "two";
    NumberType[NumberType["three"] = 2] = "three";
    NumberType[NumberType["four"] = 3] = "four";
})(NumberType || (NumberType = {}));
// 手动赋值注意:尽量不要写一些重复的值
console.log(NumberType);
// 枚举项有两种类型:常数项(constant member)和计算所得项(computed member)
// 计算所得项需要放置在已经确定赋值的枚举项之前,后面不能存放未手动赋值的枚举项
var Color;
(function (Color) {
    Color[Color["red"] = 0] = "red";
    Color[Color["blue"] = "blue".length] = "blue";
    Color[Color["green"] = 11] = "green";
})(Color || (Color = {}));
console.log(0 /* Obj.o */);
console.log(1 /* Obj.b */);
console.log(20 /* Obj.j */);
console.log(/* ABC.a */);

七、类

理解:描述了所创建的对象共同的属性和方法

①属性和方法

//  类:描述了所创建的对象共同的属性和方法
// 实例化对象
class Person {
    name: string
    age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    sayHi(str: string) {
        console.log('hi,' + str);
    }
}
let p = new Person("张三", 18)//new的时候,会执行类中构造方法constructor
p.sayHi('李四')

②静态成员(state)

只属于类自己的属性和方法(静态属性、静态方法)

// 静态方法
// 静态属性
// 只属于类自己的属性和方法
class A{
   static name1:string
    // constructor(name:string){
    //     this.name=name
    // }
   static sayHi(){
        console.log('hi');
        
    }
}
const a1=new A()
console.log(A.name1);
A.sayHi()
// console.log(a1.name);报错
// a1.sayHi()报错

③继承

*调用父类的构造函数,使用的super

*可以调用父类的方法,还可以重写这个方法

// 总结:类与类之间存在继承关系,通过extends进行继承
// 子类可以调用父类的方法,通过super
// 子类还可以重写父类的方法

// 扩展现有的类,通过继承
// 继承:类与类之间的关系
// 子类继承父类
class Animal {//父类
    name: string
    age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    sayHi(str: string) {
        console.log('hi,' + str);

    }
}
// 子类
class Dog extends Animal {
    constructor(name: string, age: number) {
        // 调用父类的构造函数,使用的super
        super(name, age)
    }
    // 可以调用父类的方法,还可以重写父类的方法
    sayHi() {
        console.log('我是dog类的sayhi方法');
        super.sayHi('狗狗')
    }
}
const a=new Animal('小猫',3)
a.sayHi('小猫')
const d=new Dog('拉布拉多犬',2)
d.sayHi()
// 总结:类与类之间存在继承关系,通过extends进行继承
// 子类可以调用父类的方法,通过super
// 子类还可以重写父类的方法

④存取器:可以帮助我们控制对对象成员的访问

get  属性(){}

set  属性(){}

// 存取器,可以帮助我们控制对对象成员的访问
class Name {
    firstName: string
    lastName: string
    constructor(firstName: string, lastName: string) {
        this.firstName = firstName
        this.lastName = lastName
    }
    // 设置存取器
    // 读取器-->用来读取数据
    get fullName(){
        // 姓名=姓氏+名字
        return this.firstName+"-"+this.lastName
        // return "张三"
    }
    // 设置器-->用来设置数据
    set fullName(value){
        console.log(value);
        let names=value.split('-')
        this.firstName=names[0]
        this.lastName=names[1]
    }
}
const n=new Name('张',"大炮")
console.log(n);
n.fullName="张-三丰"
console.log(n.fullName);

⑤修饰符

①public 修饰的属性或方法是公有的(默认)

②private 修饰的属性或方法是私有的

③protected 修饰的属性或方法是受保护的

// public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
// private 修饰的属性或方法是私有的,不能在声明它的类的外部访问,包括其子类也不能,但是这个属性和方法是可以被继承的
// protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
class B{
   public gender:string//公有的属性
   private name1:string//私有的属性
   protected age:number//受保护的属性
   public constructor(name:string,age:number){//公有的方法
        this.name1=name
        this.age=age
    }
    public p(){
        console.log(this.name1);
        console.log(this.age);
        
    }
}
class C extends B{
    constructor(name1:string,age:number){
        super(name1,age)
    }
    play(){
        // console.log(this.name1);报错
        console.log(this.age); 
    }
}
const b=new B("张三",12)
const c=new C('张三丰',13)
// console.log(c.age);

// console.log(b.name1);
// b.p()
c.play()

 ⑥readonly修饰符

readonly age:number//只读属性,但是在构造函数是可以修改的 

 readonly以及三个修饰符定义在参数上,那就是创建并且初始化的age参数

class X {
    // readonly age:number//只读属性,但是在构造函数是可以修改的
    // readonly以及三个修饰符定义在参数上,那就是创建并且初始化的age参数
    // constructor(readonly age:number){
    // constructor(public age: number) {
    // constructor(private age: number) {
    constructor(protected age: number) {
        // this.age=age
    }
    update() {
        // this.age=15 报错,不能被修改 ,只读属性
    }
}
const x = new X(13)
console.log(x);
// x.age=15

⑦抽象类 abstract 

*为子类服务

abstract class Y {//定义一个抽象类,为子类服务
    abstract name: string//抽象属性
    // constructor(name){
    //     this.name=name
    // }
    abstract sayHi()//不能有具体实现
}
// 不能够实例化
class Z extends Y {
    name: string
    constructor(name) {
        super()
        this.name=name
    }
    //在子类中去具体实现抽象类中抽象方法
    sayHi(){
        console.log('hi');
        
    }
}
const z = new Z("张三")
console.log(z.name);
z.sayHi()

⑧类的类型(和接口差不多,对类的实例对象的约束)

class Car {
    name: string
    constructor(name: string) {
        this.name = name
    }
}
class Ben extends Car {
    age:number
    constructor(name) {
        super(name)
    }
}
// const car: Ben = new Car('')
const ben: Car = new Ben("")

⑨类实现接口 ( implements )

interface ISing {
    // 这个方法是没有任何的实现
    sing()
}
interface IDance {
    dance()
}
class P implements ISing, IDance {//人 唱歌,跳舞
    sing() {
        console.log('唱歌');
    }
    dance() {
        console.log('跳舞');

    }
}
class An implements ISing, IDance {//动物 唱歌,跳舞
    sing() {
        console.log('唱歌');

    }
    dance() {
        console.log('跳舞');

    }
}
const p1 = new P()
const an = new An()
p1.sing()
an.sing()
p1.dance()
an.dance()

**接口继承接口 :接口可以继承其他的多个接口的

interface IRun {
    run()
}
interface ISwim {
    swim()
}
// 接口可以继承其他的多个接口的
interface IActive extends IRun, ISwim {
    
}
// ...
class I implements IActive {
    run() {

    }
    swim() {
    }
}

10、接口继承类:接口继承类中的实例属性和实例方法

class NewPerson{
    name:string
    constructor(name:string){
        this.name=name
    }
    sayHi(){
        console.log('hi');
        
    }
}
interface IPerson extends NewPerson{//接口继承类中的实例属性和实例方法
    age:number
}
let person:IPerson={
    name:"",
    age:18,
    sayHi(){

    }
}

11、声明合并

// 函数合并-->函数重载

// 接口合并:合并的属性的类型必须是唯一的

// 类的合并

// 函数合并--》函数重载
// 接口合并
// 合并的属性的类型必须是唯一的
// 类的合并是一样的和接口的
interface Cat {
    name: "小橘",
    gender:"女"
}
interface Cat {
    name: "小橘",
    age: 3
}
const cat: Cat = { name: "小橘", age: 3,gender:"女" }

八、泛型

①简单使用(写一个变量T,使用时再明确T的类型)

// 需求:定义一个函数,传入两个参数,第一个参数是数据,第二个参数是数量,
// 函数的作用:根据数量产生对应个数的数据,存放在一个数组中
// (123,3)-->[123,123,123]
// 数值
// T 表示任意输入的类型
function getArr<T>(value: T, count: number): T[] {
    const arr: T[] = []
    for (let i = 0; i < count; i++) {
        arr.push(value)
    }
    return arr
}
// 原则上不推荐使用any
// 使用泛型,在定义时不需要先确定类型,而是使用的时候再去确定
// 如果没有确定的话。就会走类型推断
console.log(getArr(123,3));
console.log(getArr<string>("123",3)); //这里<string>可写可不写,会走类型推断
// [123,"",true,{},[]]

②多个泛型参数的函数(无疑多写一个泛型变量)

function updateArr<T, U>(t: [T, U]): [U, T] {
    return [t[1], t[0]]
}
console.log(updateArr<string, number>(['123', 123]));
console.log(updateArr<boolean, number>([true, 123]));

③泛型约束(可以通过接口实现)

// 获取一个参数的长度
// 泛型约束,约束这个任意输入的类型,必须要有length属性
interface ILength{
    length:number
}
function getLength<T extends ILength>(x:T):number{
    return x.length
}
console.log(getLength("123"));

④泛型接口

// 定义一个泛型接口(第一种写法)
// interface IArr {
//     <T>(value: T, count: number): Array<T> //这是函数接口
// }
interface IArr<T>{   //第二种写法
    (value: T, count: number): Array<T>
}
let getArr1: IArr<string> = function <T>(value: T, count: number): T[] { //这里的IArr<string> 对应第二种写法
    const arr: T[] = []
    for (let i = 0; i < count; i++) {
        arr.push(value)
    }
    return arr
}
console.log(getArr('123',3));
// 简单例子
interface IPerson<T>{
    name:T
}
let p:IPerson<string>={
    name:""
}
let p1:IPerson<number>={
    name:123
}

⑤泛型类(用法差不多)

class Person<T>{
    name: string
    age: T
    constructor(name: string, age: T) {
        this.name = name
        this.age = age
    }
}
const person = new Person<string>("123","18")
const person1 = new Person<number>("123",18)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值