TypeScript

TypeScript

1.开始TS

ECMAscript,javascript,typescript的关系

ECMAscript是js的标准,是语法规范,而TS是js的超集.

安装TS

 npm i typescript -g

然后创建一个hello.ts

然后运行

tsc hello.js

然后可以看见多出了一个hello.js文件

node hello.js

优化编译

当编写一个函数的时候,去调用一个函数

function hello(a,b){
    console.log(a,b)
}

hello("zhangsan","lis")

然后将这个ts转化为js,转化成功之后,ts文件报错:

在这里插入图片描述

  1. 解决TS和js的冲突问题

    tsc --init 生成配置文件,在配置文件中的77行,可以先注释掉严格模式

  2. 自动编译

    tsc --watch 一旦ts文件发生了变化就会自动去转化为js文件

  3. 发出错误

    tsc -noEmitOnError hello.ts 当有ts有错误的时候,就不会转化为js

将严格模式的注释去除,会发现报错,这个错就是

在这里插入图片描述

函数的参数没有指定类型.

显示类型

参数:类型

a:string

function hello( a : string,b:Date){
    console.log(a,b)
}

hello("wangwu",new Date())

降级编译

ts是ES6的,怎么降级?

在tsconfig.json中

“target”: “es5”

严格模式

每个人的严格模式是不同的,可以进行个人定制化设置.

“strict”: true, 进行类型检查,开启严格模式

“noImplicitAny”: true, 检查any类型

“strictNullChecks”: true, 检出null 和undefined

    "strict": true,                                      
    "noImplicitAny": true,                          
    "strictNullChecks": true, 

但是实际上,只用开启strict": true,就会自动检查其余两项

2.数据类型

基元类型

string number boolean

let str :string = "hello string";
let num : number = 123;
let boo : boolean = false;

数组类型

type[] Array

let arr: number[] = [1,2,3];
let arr2: Array<number> = [1,2,3];

第一种定义方法type可以是任何的基元类型.

第二种泛型的方式,传入一个类型,然后这个数组的元素类型就是统一的.

any类型

不希望某个特定的值导致类型错误检查.

let obj : any = {
    x : 0
}

类型注释

在这里插入图片描述

函数返回值类型注释

在这里插入图片描述

函数参数为对象类型

在这里插入图片描述

function printCode(pt:{name:string;age:number}) : void{
    console.log(pt.name)
    console.log(pt.age)
}

printCode({
    name:'zhangsan',
    age:12
})

值得注意的是,参数是对象时,每个对象的属性使用分号隔开的,当然,逗号也是可以的.那么问题来了,可选参数怎么处理呢?

是可选参数的时候,在那个属性上加一个?就可以了

function printCode(pt:{name:string,age?:number}) : void{
    console.log(pt.name)
    console.log(pt.age)
}

printCode({
    name:'zhangsan'
})

联合类型

在这里插入图片描述

let strs : number|string = "123";
function fun1(names: string | number){
    console.log(typeof names)
}

fun1("zhangsan");
fun1(1232344);

类型别名

有点像自定义类型

在这里插入图片描述

就是给类型起别名.

用type 关键字

type Point = {
    x : number,
    y : number
}
function printCode(pt: Point){
    console.log(pt.x+pt.y)
}
type Id = number | string
function ids (id: Id){
    console.log('====================================');
    console.log(id);
    console.log('====================================');
}
printCode({x:1,y:3});
ids(45)

起别名的扩展:相当于继承:

type Person = {
    name: string,
    age: number
}
// 相当于继承了
type Student = Person & {
    honey: boolean
}
// 实例化
 let student : Student  = {
     name: 'zhangsan',
     age: 12,
     honey: true
 }

 console.log(student)

接口

在这里插入图片描述

用关键字interface来定义接口

interface Point{
    x: number,
    y: string
}

function fun3(pt: Point){
    console.log(pt.x)
}
fun3({
    x: 3,
    y: 'string'
})

接口的扩展:相当于继承

interface Person{
    name: string,
    age: number
}
// 相当于继承
interface Student extends Person{
    honey: boolean
}
// 实例化
 let student : Student  = {
     name: 'zhangsan',
     age: 12,
     honey: true
 }

 console.log(student)

在interface中可以同名听译类型,而type不可以,同名的类型会将属性合并.

interface Person  {
    name: string,
}

interface Person{
    age: number
}
let person: Person = {
    name: 'zhansan',
    age: 12
}
console.log(person);

type和interface的区别

  1. type不支持重复定义,而interface支持,可以通过同名来扩展字段
  2. type的扩展方式是用& type Student: Person & {},而interface是用关键字extends
  3. type的定义是赋值式,type Student = {},而interface 是 interface Person{}

类型断言

在这里插入图片描述

断言相当于强转就是把一种数据类型转化为可能的另一种数据类型

let str  = <string>"1234";
let str1 = "1234" as string

cons name =( "1234" as unknown) as string

文字类型

在这里插入图片描述

文字类型就相当于是一个常量,定义了就只能传递这个值,不可以改变,就相当于是const当以的常量..

如果函数参数类型是文字类型’hello’,就意味着,函数的参数只能是’hello’

const hello = "helloworld"
// hello = "ee"

// 定义文字类型,那这个x的值就只能是hello
let x: 'hello' = "hello";
console.log(x);
// 如果参数类型是文字类型'hello',就意味着,函数的参数只能是'hello'
function fun(s: 'hello'){
    console.log(x)

}
fun('hello')

数字的文字类型使用是一样的

function fun(a: 1){
    console.log(a);
    
}
// 这里就只能传入1
fun(1)

null和undefined

let x: null = null;
let y: undefined = undefined;

枚举

在这里插入图片描述

通过enum关键字来定义

enum Dir{
    Upo = 1,
    down,
    left,
    right
}
// 设置了第一个,后面的数据会一次增加
console.log(Dir.Upo);  // 1
console.log(Dir.down);//  2

不太常用的原语

在这里插入图片描述

// 将target:es2020
const onHand : bigint = BigInt(1000)
const an:bigint = 100n
console.log(onHand,an);


const a = Symbol("name")
const b = Symbol("name")
console.log(a===b);  //false

3.类型缩小

当一个变量的类型是一个联合类型的时候,使用可能会出错,这个时候就需要将类型的范围变小.怎么将范围变小呢,通过typeof还进行类型守卫.

function pri(strs: string | string[] | null){
    if(typeof strs ==='string'){
        // todo
    }else if(typeof strs === 'object'){
        // todo
    }else{
        //todo
    }
}

通过类型的判断来对参数进行相应的处理

真值缩小

条件,&&,||,if语句,布尔否定

就是需要判断一个值不是 null undefined 0n 0 ’ ’ 等

function pri(strs: string | string[] | null){
    if(typeof strs ==='string'){
        console.log(strs);
        
    }else if(strs && typeof strs === 'object'){
        for(let s of strs){
            console.log(s);
            
        }
    }else{
        console.log(strs);
        
    }
}

就是通过一些运算来排除参数的值为空的情况.

function fun(values: number|null){
    if(!values){
        console.log("参数为空");
    }else{
        console.log(values*100);
        
    }
}

等值缩小

1.判断一个参数不等于null,就会自动判断也不等于undefined,利用!= 或==来判断

function fun(str: null|undefined|string){
    if(str != null){
        console.log(str)
    }
}
fun("333")  // 333
fun(null)  // 没有打印
fun(undefined)  //没有打印

2.如果判断两个参数==,他会自动去找这两个参数的类型一样,如果一样才判断

function fun(a:string|number,b:string|null){
    if(a==b){
        console.log("==")
    }else{
        console.log(a);
        console.log(b);
    }
}

in操作符

判断一个参数是否具有某一个方法或参数,如果所有那这个参数就是这个方法所属的类型.

type Fish = {swin:()=>{}}
type human = {swin?:()=>{}}
type bird = {sky: ()=>{},sss:()=>{}}
function fun(anim:Fish|human|bird){
    // 如果 anim有sky方法,就可以判断,它可能是bird类型
    if("sky" in anim){
            anim.sss()
    }else{
        (anim as Fish).swin()
    }
}

instancesof

x instancesof Foo 判断x是不是一个类的实例

分配缩小

在这里插入图片描述

就比如一个三目运算符,这个时候的x,系统就会自动根据两边的值来给x赋上数据类型,在这里x的类型就是 number|string,

如果你再想给x赋值成true就会报错.

控制流分析

就是通过if判断加上typeof的判断来控制变量的类型

never类型与穷尽性检查

表示一种不存在的状态.

never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。这意味着声明为 never 类型的变量只能被 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) {}
}

4.函数

函数类型表达式

在这里插入图片描述

function a(fn:(a:string) =>void){
    fn("hello")
}
function b(s:string){
    console.log(s);
}
gener(b)

函数a的参数传入的是一个函数类类型,fn,函数类型怎么定义的呢? fn:(a:string) => void 这个函数传入个string类型的数据,返回值为void,其中b函数,就是这个函数类型的具体实现

为了直观的表达.改为下面的方式,

type func = (a:string) => void
function a(fn:func){
    console.log("hello")
}
function b(s:string){
    console.log(s);
}

a(b)

调用签名

在这里插入图片描述

type DescFunc = {
    // 函数的属性
    desc : string,
    // 函数的定义
    (str:string):string
}
// 创建一个函数,将构造的这函数类型传入
function todos(fn: DescFunc){
    // 调用属性
    console.log(fn.desc);
    // 函数可以直接调用,实际上DescFunc就式自己定义的函数
    // 调用函数
    fn('hello')
}
// 实现这个具体的函数类型DescFunc
function f1(s:string){
    return s;
}
f1.desc = "hello";
// 调用函数,传入参数f1
todos(f1);

构造签名

在这里插入图片描述

Ctor是一个类

泛型函数

在这里插入图片描述

function fu<T>(arr: T[]): T | undefined{
    return arr[0]
}

fu<number>([1,2,3,4])
fu(['1','2'])

如果函数的返回值不确定,可以用泛型来解决.泛型就是随机应变.

限制条件

在这里插入图片描述

function fun <T extends {length:number}> (a:T,b:T){
    if(a.length>b.length){
        return a.length
    }else{
        return b.length
    }
}
console.log( fun([1,2,3],[1,2,3,4,5,6]));

不能保证a和b没有length这个属性,让泛型T去继承length这个属性

指定泛型参数

在这里插入图片描述

就是给泛型指定类型.

编写优秀通用函数的准则

在这里插入图片描述

可选参数

用?选择

function fun(str?: number){
    console.log(str);
    
}
fun()

永远不要在回调函数中写一个可选参数.

函数重载

前两个式重载签名

第三个式实现重载签名

function sum(a:number):Date;
function sum(b:number,c:number):Date;
function sum(a:number,b?:number,c?:number):Date{
    return new Date();
}

编写好的重载

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zRNKCoJ3-1648267501861)(assets/1645860199637.png)]

函数内的this

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7GvSGujA-1648267501862)(assets/1645860785339.png)]

其他类型

void object unknow never Function

参数的展开运算符

… 形参展开

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-reW3truM-1648267501864)(assets/1645861091853.png)]

将形参合并到一个参数中,在这个函数中.10对应到n,而剩余的参数自动合并到m中

实参展开

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2SBfdzaN-1648267501864)(assets/1645861358977.png)]

5.对象

interface Person{
    name: string,
    age: number
}

type Student ={
    name: string,
    age: number
}
function fun(p: Person){
    console.log(p);
    
}

可选属性

就是给属性加上问号

type Student ={
    name: string,
    age?: number
}
function fun(p: Student){
    console.log(p);
}
fun({name:"zhangsan",age:12})
fun({name:"zhangsan"})

只读属性

不会改变值加上readonly关键字

type Student ={
   readonly name: string,
    age?: number
}
function fun(p: Student){
    console.log(p);
    // 会报错
    //p.name="h"
}
fun({name:"zhangsan",age:12})

如果把readonly加在类上面,这个类中的属性是可以改变的

type Student ={
   readonly name: string,
    age?: number,
    readonly stu:{
        as: string
    }
}
function fun(p: Student){
    console.log(p);
   p.stu.as="hh"
}

索引签名

interface Student{
    // 索引的名字不确定,单数知道索引的类型式number,然后索引的值为string
    [index: number]: string
}
let yeStu: Student = ['q','b']
console.log(yeStu[0]);

就是用来规定类中的属性的类型和属性值的类型.

扩展类型

用extends来扩展就是继承

interface Person{
    name: string,
    age: number
}
// 相当于继承
interface Student extends Person{
    honey: boolean
}

交叉类型

interface A{
    name: string
}
interface B{
    age:number
}
// 通过type 让AB具有A和B和属性
type AB = A & B;
let AB = {
    name: 'zhangsan',
    age:12
}

// 不同type也可以
function func(C: A & B){
        //todo
}

定义交叉类型有两种,第一种是通过type和&来完成,第二种是作为函数的参数.

泛型对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TgVCaE5J-1648267501865)(assets/1645865205391.png)]

interface Person<T>{
    name: T,
    age:number
}
let person: Person<string>={
    name: '张三',
    age: 12
} 

6.类型操纵

泛型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5uo2ih46-1648267501865)(assets/1645866061982.png)]

泛型类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y8TnOEDW-1648267501866)(assets/1645866592097.png)]

function fun<T> (ag:T) : T {
    return ag;
}
let myFun: <T>(ag: T) => T = fun 

interface Inter{
    <T>(ag: T) : T
}

let MyFun1 : Inter = fun;

将泛型定义成一中数据类型

还有一种方式,这种方式更好.

interface Inter<T>{
    (ag: T): T
}

let Myfun: Inter<string> = fun
泛型类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wzRsKXif-1648267501867)(assets/1645867099053.png)]

class Person<T>{
    name: T,
    add: (x: T,y: T) => T
}
let person = new Person<string>()
person.name = "zhangsan"
person.add =function ('a','b'){return "hello"}
泛型约束

就是用extends来约束,就是告诉开发者,在用这个类的时候,传入的泛型类型,必须带有一些类型

function fun<T extends string>(arg:T){
    console.log(arg.length);  
}
在约束中使用类型参数

keyof就是约束key一定要是Td的一个属性

// 两个参数,一个是类.一个是类的属性  keyof就是约束key一定要是Td的一个属性
function fun<T,key extends keyof T>(obj:T,key:key){
    console.log(obj[key]); 
}

let x = {
    a:1,
    b:2
}
fun(x,"a")

<T , key extends keyof T> key extends keyof T的以上就是key一定是T的一个属性

在泛型中使用类类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cmRv94du-1648267501868)(assets/1645867951207.png)]

keyof
type Person = {
    name: string,
    age: number
}

type P = keyof Person;

let  p1 : P = "name";
let p2: P = "age";
let p3: P = "dd";  //报错合格

这个P就只包含name和age

typeof

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JDGuUqYm-1648267501869)(assets/1645871406285.png)]

判断一个变量的类型

索引类型
type Person={
    name: string,
    age: number
}

type Name = Person["name"]
let name1: Name = "zhangsan"

条件类型

三目运算

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OwbKcA3i-1648267501870)(assets/1645872363283.png)]

7.类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xIlkICJH-1648267501871)(assets/1645879746309.png)]

// 如果不加!会报没有初始化值的错误
class Person{
    name!: string
    age!: number
}
let person = new Person()
person.name = "zhangsan";
person.age = 10;
console.log(person);

或者用构造函数

class Student{
    name
    age
    constructor(){
        this.name='张三',
        this.age = 10
    }
}

console.log(new Student());

readonly

// readonly 可以在构造函数中被二次修改
class Person{
    readonly name: string = "hello"
    constructor(){
        this.name = "world"
    }
}

// 但是不可以在外面二次修改

构造器

1.构造函数不能有类型参数

2.构造函数不能有返回类型注释

class Person{
    name: string
    age: number
    constructor(name: string,age: number) {
        this.name = name
        this.age = age
    }
}
let p = new Person('zhangsan',12);

方法

除了有类型注释以外,和js方法没有什么区别

getter/setter

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wPkbJfyx-1648267501872)(assets/1645882576231.png)]

class C{
    _length = 0
    get length(){
        return this._length
    }
    set length(value){
        this._length = value
    }
}
let c = new C()
c.length
c.length = 100

索引签名

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1eUNXDXz-1648267501873)(assets/1645883184795.png)]

索引可以约束类中属性的定义规则

class Person{
    [s: string]: string | (()=>boolean)
    name = 'zhangsan' 

    check(){
        return true;
    }
}

implement实现接口

interface Person{
    fun(): void
}
class Student implements Person{
     fun() {
        //todo
    }
}

一个类可以实现多个接口

extends

和前面的一样

重写

重写发生在继承中,重写父类的方法.

class Person{
    fun(){}
}
class Student implements Person{
    // 重写父类的方法
     fun(name?: string) {
        
    }
}

初始化顺序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FXlLjZSe-1648267501874)(assets/1645885049801.png)]

继承内置类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G3kMljRg-1648267501875)(assets/1645925333815.png)]

成员可见性

public 默认是可见的

protected 在内部和子类访问

private 只能在内部访问

静态成员

用static修饰,可以直接用类名访问

类的静态区块

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ozuWe5Yb-1648267501876)(assets/1645926612311.png)]

泛型类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IqOx4Bsu-1648267501876)(assets/1645927214624.png)]

this类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ntgUBqP-1648267501877)(assets/1645927830511.png)]

抽象类和成员

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZY5Med7o-1648267501878)(assets/1645928804564.png)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈斌-cb

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值