ts详解和js区别

ts和js区别

阮一峰ts官网http://ts.xcatliu.com/introduction/what-is-typescript.html
ts官网https://www.tslang.cn/docs/home.html

ts就到vue3或者是react中去使用吧,在vue2中 使用ts基本上是给自己添加烦恼.

使用简介链接

typescript简介

typescript 是javascript类型的超集, 可以编译成纯javascript, ,可以跨浏览器,跨平台运行

如果你很在乎开发速度,快速迭代,那么建议你继续用 JavaScript。如果你需要高稳定性,那么建议你使用 TypeScript。

编译TS

手动编译:tsc home.ts (执行命令就可以将ts代码编译成另一个同名js文件)

运行:node home.js

自动编译

1). 生成配置文件tsconfig.json
    tsc --init
2). 修改tsconfig.json配置
    "outDir": "./js",
    "strict": false,//关闭严格模式
3). 启动监视任务:
    终端 -> 运行任务 -> 监视tsconfig.json

在tsconfig.json同级文件下新建index.html和index.ts
执行上述 3 步骤会生成同名index.js文件
在index.html中引入idnex.js文件并浏览器运行

完成自动编译:之后修改ts文件可直接输出

数据类型

js基本数据类型:number string boolean undefined null symbol
js的引用数据类型: Object array function

基础类型链接

let 变量名:数据类型 =// 数据类型定义
let num:number = 100;
let str:string = 'hello'
let flag:boolean = true;
let timer:undefined = undefined;
let obj:null = null;

默认情况下null和undefined是所有类型的子类型 ; 就是说你可以把 null和undefined赋值给任何类型的变量

数组

let 变量名:[number, string] = [1, '3'];
let 变量名:[number | string, string] = [1, '3'];

let str:[number | string, string] = [1, "3"];
console.log(str);//[1, "3"];
数组的类型
  1. 「类型 + 方括号」表示法
let str1:number[]=[1,3,4,5];
  1. 元组: 限定数组中每个元素的类型 , 同时也限定了数组中元素的个数;
    (元组不是数组,只是刚好符合数组的规范)
let arr2:[number, string] = [1, 'hello']
  1. 通过 数组的泛型 Array<数据类型>
let arr3:Array<number> = [21,4,45,23]
let arr4:Array<string> = ['ajds']
  1. 通过接口定义数组 [index:number] 限定的是数组索引值的类型, 后边是限定数组中元素的类型
interface a{
    // [index:number]:number
    [index:number]:string
}

// let arr5:a = [1,4,5,6]
let arr5:a = ['234', '345', '35432']

允许数组中出现任意值:any[]

let arr6:any[] = [23, '345', {name:'zadf'}]

枚举

定于枚举类型: 使用枚举我们可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。 TypeScript支持数字的和基于字符串的枚举。

//  通过关键字 enum 定义枚举类型
//  一旦定义枚举类型 : 数字类型的枚举,会存在默认值,默认值从0开始 ; 默认值会依次递增
enum Per{
     //  随意自定义 ; 自定义的是常量的名字,而没有给常量赋值,常量的默认是从0开始的
    A,//默认A=0
    b,//B=1
}
/*Per[1] 这是通过枚举类型的值 获取枚举类型的名字
 []中的数字是 枚举类型的值; 而不是索引值 */
console.log(Per[1]);//b
//  可以手动指定枚举类型的值
enum E {
    a,      // 第一个枚举名没有指定值,则默认是从0开始
    b,
    d = 12, // 指定了值,则使用指定的值
    c,      // 没有指定值,会从上一个枚举值自动递增
    f = 16
}

//console.log(E[0], E[12],E[13]);//a  b   c

 //console.log(E.a, E.b, E.c);//0  1  13
 console.log(E['a'], E['b'], E.c);//0  1  13

// 访问枚举类型有两种方式: 
// 第一种是通过枚举的值访问枚举类型名  枚举变量名[值]; 
// 第二种是通过枚举类型名访问枚举类型值  枚举变量名.枚举常量名   或者 枚举变量名['枚举常量名'] ;

任意类型any

使用 any 关键字 定义任意类型

let 变量名:any = value;
// 后期可以随便进行更改
例子  let str:any=100;
console.log(str);//100

2.1. 空值
代表该函数没有任何返回值

 function alertName(): void {
    alert('My name is Tom');
}

声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null

类型推断

TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是类型推断

/* 定义变量时赋值了, 推断为对应的类型 */
let x = 100; // 这种情况下 ts 就会使用类型推断
 x= 'abc' // error

如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查:

  • 隐式任意类型
let str; // 通过类型推论 推断为 任意类型
str = 'hello';
str = 100;

联合类型

联合类型(Union Types)表示取值可以为多种类型中的一种。 使用 | 符号

let 变量名: 数据类型1 | 数据类型2 |  ... = value ;// value 可以是 类型的任意一个; 后期可以更改为定义的类型中任意一个


 let arr:number|string=100
 arr="hello"
 console.log(arr);//hello

类型断言

(Type Assertion)可以用来手动指定一个值的类型

语法:        
  方式1    <类型>值
  方式2   值 as 类型    tsx中只能用这种方式
//  接口约束  类型断言
interface Cat {
    name: string;
    run(): void;
}
interface Fish {
    name: string;
    swim(): void;
}

// 类型断言 : 我知道自己在干嘛,所以不需要ts帮我们进行类型判断
function getName(animal: Cat | Fish) {
    //return animal.name;//HEISE
    // animal.run();报错
    //animal.swim();报错
    //  类型断言 (我知道自己要去用Fish接口)
    (animal as Fish).swim()
}

let str = getName({
    name: 'HEISE', swim: function () {
        console.log("函数")
    }
})
console.log(str);//函数

接口

在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。
接口是对象的状态(属性)和行为(方法)的抽象(描述)

//定义了一个接口 Person,接口名字首字母大写
interface Person {
    name: string;
    age: number;
}
//接着定义了一个变量 tom,它的类型是 Person
let tom: Person = {
    name: 'Tom',
    age: 25
};
console.log(tom.name);//Tom
  1. 可选属性
    定义可选属性 通过 ? : 如果有一些属性是可有可无,可以定义为可选属性,通过 在属性名后边添加 ? 实现
interface Person{
    name:string;
    age:number;
    sex?:string;
    hariColor?:string
}
let stu:Person = {
    name:'hello',
    age:18,
    sex:'nv',
    hariColor:'123984'
}
console.log(stu);
  1. 定义任意属性(也是可有可无)

[propName:数据类型] :any 使用 [propName: string] 定义了任意属性取 string 类型的值。

interface Person {
    name: string;
    age?: number;//可选属性
    [propName: string]: any;//任意类型
}

let tom: Person = {
    name: 'Tom',
    gender: 'male'//可以是任意类型
};
  1. 定义只读属性
    通过 readonly 关键字
    只读: 只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候:
interface Person {
    readonly name:string;
    age:number
}
//只读  在该环节生效的
let stu1:Person = {
    name:'张三',
    age:19
}
//console.log(stu.name);
stu1.name="李四"//只读属性不允许修改

函数返回值 ,返回值是对象

interface Person {
    name: string;
    age: number
}
//函数返回值 ,返回值是对象
function Stu1(a:Person):{name:string, age:number}{
    let newStu = {name:'张三', age:100}
    if(a.name){
        newStu.name = a.name;
    }
    if(a.age){
        newStu.age = a.age;
    }
    return newStu
}
 var res = Stu1({name:'李四', age:18})
console.log(res);//{name:'李四', age:18}

函数

基本示例

函数声明式

 function fun(a:number, b:number){ }

函数类型

函数表达式

 let fun2 = function(a:number, b:number){ }
  • 函数返回值的定义
//  限定返回值
function fun(a:number):number{//第二个number就是限定的返回值(也叫输出)
    return a + 100;
}
console.log(fun(100));//200
// 函数存在返回值
function  函数名(参数名:参数类型):返回值的类型{
    return value; // value 比如符合你定义的类型
}
function sum(a:number,b:number):number{
    return a+b;
}
console.log(sum(1,2));//3
// 函数没有返回值 使用void 关键字
function  函数名(参数名:参数类型):viod{
    // 函数不需要返回值
}

function red(a,d):void{
console.log(a);
}
red(100,200)
// 如果函数的返回值是一个对象
function f(n:string, a:number):{name:string,age:number}{
    return {name:n, age:a}
}

function f(n:string, a:number):{name:string,age:number}{
    return {name:n, age:a}
}
console.log(f("hello",100));//{ name: 'hello', age: 100 }

书写函数的完整格式

//   针对的是函数表达式的方式  
//  定义函数时的变量名可以不同,但是数据类型必须一致
//  区分 => 和 es6 的箭头函数    箭头 number这里是规定输出值的类型,不是箭头函数
let fun2:(x:number, y:number) => number = function(a:number, b:number):number{
    return a + b;                                                
}
console.log(fun2(10,20));//30
(x:number,y:number)=>number当前的这个函数的类型
function(X:number,y:number):number{return x+y}就相当于符合上面的这个函数类型的值

箭头如果实在函数表达式中(就是声明函数时使用的),意味着是指定函数返回值的类型,除此以外代表都是箭头函数

let fun2:(x:number, y:number) => string = (a:number, b:number):string=>{//第二个箭头才是箭头函数
    return (a + b).toString();
}
console.log(fun2(10,20));//30

可选参数和默认参数

  1. 可选参数
function f(x?:number){}
  1. 默认值参数
function f(x:number, y = 100 ){}
  1. 剩余参数 我们可能不确定参数个数: 这个时候可以使用剩余参数 (rest参数)
function fun(a:number, b:number, ...args:number[]){
    console.log(a, b, args);    //1 3 [ 4, 6, 8 ]
}

fun(1, 3, 4, 6, 8)

函数重载

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

函数重载或者方法重载适用于某个功能一样,但是细节有不一样
比如说一个函数有多个参数,每一个参数代表不同意义 这个时候就可使用函数重载

//  定义函数重载类型
function 函数名(参数:数据类型1):返回值类型1;
function 函数名(参数:数据类型2):返回值类型2;
// 函数的实现的定义
function 函数名(参数:数据类型1 | 数据类型2):数据类型1 | 数据类型2{
    // 逻辑处理
}

function 函数名(参数:any):any{
    // 逻辑处理
}

具体实现:

/* 1  定义重载函数的类型 : 定义的是函数类型 */
function add(x: string, y: string): string
function add(x: number, y: number): number
/* 2 定义函数   函数类型定义和函数定义之间不能 存在任何代码 */
function add(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(add("1", "2"));//12
console.log(add(1, 2));//3
console.log(add("1", 2));//undefined
//上述例子add("1", 2)(在没有定义重载函数的类型前):字符串和数字拼接,ts应该是报错的,因为不符合规则
所以推出重载函数

泛型

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,

而在使用的时候再指定类型的一种特性。

 泛型: <自定义的的值> 代表数据类型,后期由你传入的类型决定 比如:   <T>  <M>  <A>

其中 T 代表 Type,在定义泛型时通常用作第一个类型变量名称。但实际上 T 可以用任何有效名称代替。除了 T 之外,以下是常见泛型变量代表的意思:
K(Key):表示对象中的键类型;
V(Value):表示对象中的值类型;
E(Element):表示元素类型。

function f<M>(arg:M):M{
 //第一个m是泛型   第二个是传入值的类型    第三个是返回值类型
    return arg;
}

console.log(f<string>('hello'));//hello  
解释:这里的f<string>是什么类型,上面的M就是什么什么类型,所以后期可指定值类型

泛型约束

//  泛型约束  
//在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法:
function test<T>(a: T[]):T{
    console.log(a.length);    
    // return a.length; // 报错: 泛型约束(因为这个时候你还不知道返回值是什么类型)
    return a[2]
}
 console.log(
    test<number>([1,3,54,6]));//  4   54
interface Ilength {
    //定义一个接口,用来约束将来的某个类型中必须要有lenght属性
    length: number
}

function test<T extends Ilength>(a: T): number {
    return a.length;
}

console.log(test<string>("穿过挪威的森林"));//7
console.log(test<number>(123));// !!类型“number”不满足约束“Ilength”

在这里插入图片描述

泛型接口

extends(继承)和 implements(实现)的关系
在定义接口时, 为接口中的属性或方法定义泛型类型 在使用接口时, 再指定具体的泛型类型

interface IbaseCRUD<T> {//定义一个泛型接口
    data: T[]
    add: (t: T) => T
    getById: (id: number) => T
}

class User {
    id?: number //id主键自增
    name: string //姓名
    age: number //年龄

    constructor(name, age) {
        this.name = name
        this.age = age
    }
}

class UserCRUD implements IbaseCRUD<User> {
    //用来保存多个User类型的用户信息对象
    data: Array<User> = []
    add(user: User): User {
        user = { ...user, id: Math.random() }
        this.data.push(user)
        // console.log('保存user', user.id)
        return user
    }
    //方法根据id查询指定的用户信息对象
    getById(id: number): User {
        return this.data.find(item => item.id === id)
    }
}
//实例化添加用户信息对象的类UserCRUD
const userCRUD = new UserCRUD()
//调用添加数据的方法
userCRUD.add(new User('tom', 12))
const { id } = userCRUD.add(new User('tom2', 13))
console.log(userCRUD.data)
//测试getById方法
const user = userCRUD.getById(id)
console.log("匹配到的内容", user);



在这里插入图片描述

泛型类

//定义一个类,类中的属性值的类型是不确定的,方法中的参数及返回值的类型也是不确定
//定义一个泛型类
class GenericNumber<T> {
    defaultValue: T
    add: (x: T, y: T) => T
}
//在实例化类的对象的时候,在确定泛型的类型
const g1: GenericNumber<number> = new GenericNumber<number>()
//设置属性值
g1.defaultValue = 100
g1.add = function (x, y) {
    return x + y
}
console.log("调用并输出", g1.add(10, 20));
console.log("调用并输出", g1.add(g1.defaultValue, 20));

在这里插入图片描述

es6中类的用法1
使用 class 定义类,使用 constructor 定义构造函数。

通过 new 生成新实例的时候,会自动调用构造函数。

      class Animal {
        //实例对象属性
        name;
        //构造器constructor方法是类的默认方法,定义私有的属性
        constructor(name) {
                this.name = name;
            }
            //公有的方法
        sayHi() {

            }
            //静态方法
        static say() {

            }
            //class的getter和setter
        get name() {
            return 'Jack';
        }
        set name(value) {
            console.log('setter1: ' + value);
        }
    }
    //Vue的双向数据绑定的原理,数据劫持,(object.definedProper),就是通过get和set方法实现,只能拦截一次

TypeScript 中类的用法

class Person {
    name:string;
     constructor(name:string='hello') {//hello是默认值
         this.name=name
     }
  }
  let a = new Person();//如果这里传值,就会使用
  console.log(a);//Person { name: 'hello' }
  console.log(a.name); // Jack

public private 和 protected

TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected。

public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的

class Animal {
    public name:any;//公有的属性
    public constructor(name:any) {
      this.name = name;
    }
  }
  
  let a = new Animal('Jack');
  console.log(a.name); // Jack
  a.name = 'Tom';
  console.log(a.name); // Tom

private修饰的属性或方法是私有的,只能在类的内部访问

class Animal {
    private name:any;
    constructor(name:any) {
        this.name = name;
    }
    sayHi() {
        return `My name is ${this.name}`;
    }
}

let a = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack

使用 private (私有)修饰的属性或方法,在子类中也是不允许访问的:

class Animal {
    private name:any;
    public constructor(name:any) {
      this.name = name;
    }
  }
  
  class Cat extends Animal {
    constructor(name:any) {
      super(name);
      console.log(this.name);
    }
  }

换为protected 受保护的就不会报错了

class Animal {
    protected name:any;
    public constructor(name:any) {
      this.name = name;
    }
  }
  
  class Cat extends Animal {
    constructor(name:any) {
      super(name);
      console.log(this.name);
     
    }
  }

只读属性的初始化操作,要么在声明的时候进行,要么在构造器中进行

class Animal {
  readonly name;
  public constructor(name) {
    this.name = name;
  }
}

let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
//报错Cannot assign to 'name' because it is a read-only property.
class Person2 {
    //(1) 构造函数中的name参数,一旦使用readonly进行修饰后,那么该name参数可以叫参数属性
    //(2) 构造函数中的name参数,一旦使用readonly.进行修饰后,那么Person中就有了一个name的属性成员
    //(3) 构造函数中的name参数,一旦使用readonly进行修饰后,外部也是无法修改类中的name属性成员值的
    //name;(2)
    constructor(readonly name: string = "大甜甜") {
        //(1) this.name = name; this.name中name是Person2的参数属性
    }
}
//实例化对象
const p = new Person2('小甜甜')
//p.name="真好"//(3)
console.log(p.name)

存取器

TypeScript 支持通过 getters/setters 来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。

class Person {
    firstName: string;
    lastName: string
    constructor(firstName: string, lastName: string) {
        this.firstName = firstName;
        this.lastName = lastName
    }
    get fullName() {
        return this.firstName + "_" + this.lastName
    }
    set fullName(val) {
        console.log("设置的值", val);
        let names = val.split("_")
        this.firstName = names[0];
        this.lastName = names[1]

    }
}
//实例化对象
const p: Person = new Person('东方', "不败")
console.log(p)
p.fullName = "诸葛_孔明"
console.log(p)

在这里插入图片描述

静态属性static

静态属性, 是类对象的属性
非静态属性, 是类的实例对象的属性

class Person {
    static name1: string = "小甜甜";
    constructor() {//构造函数是不能通过static来进行修饰的
    }
    static sayHi() {
        console.log("萨瓦迪卡");
    }
}
//var p = new Person();
//---通过实例对象调用属性/方法------
// console.log(p.name); //类型“Person”上不存在属性“name”
//p.sayHi()//属性“sayHi”在类型“Person”上不存在。
//---通过类.静态属性/方法 来访问该成员数据------
Person.name1 = "佐助" //通过类.静态属性来设置该成员数据
console.log(Person.name1);//小甜甜
Person.sayHi()//萨瓦迪卡

这样就不用创建类的实例对象调用属性/方法

抽象类

抽象类:包含抽象方法(抽象方法一般没有任何的具体内容的实现),也可以包含实例方法,抽象类是不能被实例化,为了让子类进行实例化及实现
内部的抽象方法
抽象类的目的或者作用最终都是为子类服务的

abstract class Animal {
    //     abstract eat() {//抽象方法  --报错-抽象方法不能有具体实现
    //         console.log("吃");
    //   } 
    /*(1) abstract name: string;  没有必要在抽象类中来一个抽象属性让子类去实现,所以不考虑 */
    abstract eat()
    sayHi() {//实例方法
        console.log('你好呀')
    }
}
//const ani=new Animal()//报错-- 不能实例化抽象类的对象!
/*定义一个子类(派生类)Dog */
class Dog extends Animal {
    // name: string = "小黄";
    /*重新的实现抽象类中的方法,此时这个方法就是当前Dog类的实例方法了  */
    eat() {
        console.log('蘸着吃')
    }
}

const dog = new Dog()
dog.eat()
dog.sayHi()//这里调用的是抽象类中的实例方法
//(1) console.log(dog.name);

在这里插入图片描述

类型别名

类型别名用来给一个类型起个新名字。
类型别名有时和接口很像,但是可以用于原始值,联合类型,元祖以及其它任何需要手写的类型
通过type 关键字定义类型别名


type Name = string;//给string起了个别名name
type NameResolver = () => string;//类型别名还可以是一个函数(定义一个函数,函数的返回值是string类型,这里的)
箭头如果实在函数表达式中(就是声明函数时使用的),意味着是指定函数返回值的类型,除此以外代表都是箭头函数
type NameOrResolver = Name | NameResolver;//综合类型
function getName(n: NameOrResolver): Name {
    if (typeof n === 'string') {
        return n;
    } else {
        return n();
    }
}
console.log(getName("string"字符串)//字符串的情况
let res=getName(function(){//else的情况
return 'hello'
})
console.log(res)//hello

上例中,我们使用 type 创建类型别名。

类型别名常用于联合类型。

声明文件

declare var num:number;//声明一个变量
 declare function jQuery(selector: string): any;//声明了一个方法
 num = 100;
 jQuery('#app')

声明文件: 扩展名时 .d.ts ; 格式: 自定义文件名.d.ts
ts 会自动查找声明文件
当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
我们通常这样获取一个 id 是 foo 的元素:

$('#foo');
// or
jQuery('#foo');

但是在 ts 中,编译器并不知道 $ 或 jQuery 是什么东西1:

jQuery('#foo');
// ERROR: Cannot find name 'jQuery'.

这时,我们需要使用 declare var 来定义它的类型2:

declare var jQuery: (selector: string) => any;

jQuery('#foo');

上例中,declare var 并没有真的定义一个变量,只是定义了全局变量 jQuery 的类型,仅仅会用于编译时的检查,在编译结果中会被删除。它编译结果是:

jQuery('#foo');

Ts入门教程链接

vue3+Ts基础链接

  • 5
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TypeScript 中的 declare 关键字用于声明某些变量、函数或类的类型,但并不实际定义它们的实现。这是因为 TypeScript 可以用来编写 JavaScript,而 JavaScript 中的许多变量、函数或类并没有明确定义它们的类型。因此,使用 declare 关键字可以帮助 TypeScript 理解这些 JavaScript 代码的类型。 declare 关键字的使用有以下几种情况: 1. 声明全局变量或函数 在 TypeScript 中,全局变量或函数应该在任何文件中都可以访问。但如果这些变量或函数没有明确定义类型,则 TypeScript 编译器可能无法正确解析它们的类型。因此,使用 declare 关键字可以告诉编译器这些变量或函数的类型。 例如,以下代码声明了一个全局变量 message,并指定它的类型为字符串: ``` declare var message: string; ``` 2. 声明模块 在 TypeScript 中,可以使用 declare 关键字来声明模块的类型。例如,以下代码声明了一个名为 MyModule 的模块,并指定它包含一个名为 myFunction 的函数: ``` declare module MyModule { function myFunction(): void; } ``` 3. 声明类的类型 在 TypeScript 中,可以使用 declare 关键字来声明一个类的类型,而不实际定义它的实现。这通常用于与第三方库集成时,以便编译器知道这些类的类型。 例如,以下代码声明了一个名为 MyLibrary 的类,并指定它包含一个名为 myFunction 的方法: ``` declare class MyLibrary { myFunction(): void; } ``` 需要注意的是,使用 declare 关键字并不会实际生成任何代码,它只是告诉编译器这些变量、函数或类的类型。因此,如果使用 declare 关键字声明一个变量、函数或类的类型,就必须确保在代码中正确地实现它们。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值