保熟的TS知识,拜托,超快超酷的好吗

简介: 这一步对于很多人来说是最简单的一步,也是最难的一步,说简单是因为这确确实实仅是入门的一步,就是一个环境配置,说难则是因为很多人无法跨出这一步,当你跨出这一步之后,你会发现后面的真的学得很快很快,现在,就让我们一起跨出这一步吧~


一篇文章带你JS-->TS,拜托,超快超酷的好吗!

如何使用TS来输出你的HelloWorld呢?


这一步对于很多人来说是最简单的一步,也是最难的一步,说简单是因为这确确实实仅是入门的一步,就是一个环境配置,说难则是因为很多人无法跨出这一步,当你跨出这一步之后,你会发现后面的真的学得很快很快,现在,就让我们一起跨出这一步吧~

step1:安装TS

cnpm i -g typescript
// 查看是否安装成功,能输出对应的版本号就对了
tsc -v


step2:编写TS代码

console.log('Hello TS');


有小伙伴就问,这也是TS的代码吗?这不是JS的代码吗?当然是,TypeScript是JavaScript的超集,因为它扩展了JavaScript,有JavaScript没有的东西,那么JS有的东西,它也是有的,你就放心使用吧~

网络异常,图片无法展示
|

step3:编译TS为JS

TS在浏览器中是无法运行的,它的出现只是为了弥补开发人员在编写JS代码的痛苦,就是无类型,这个在小型demo中是无法体现的,但一上升到大项目中,你会发现JS的any类型难以维护,这也是TS出现的原因,大家都知道Vue3是全部拿TS构建了,那么Vue3+TS+...就是现在开发的一套可能是主流技术栈了,这也更加坚定了我们学习TS的原因!

tsc .\01_Hello.ts   // 编译刚写的TS文件

之后会生成同名的JS文件,好了,现在,你可以运行你的第一句TS代码吧~

项目中如何编译多个TS文件呢?


上述的编译方式只能编译一个文件,多个文件难道需要我们一步步执行命令?这对于几乎成为主流的TS来说怎么可能会有如此低效率的编译方式,现在,让我们学习一下多个文件的编译方式:


 tsc --init  // 首先你需要使用这个命令初始化一个tsconfig.json文件


之后我们就可以在这个文件里面控制对我们整个项目中多个文件的编译方式了,哈~再也不用每个文件都执行一次tsc+hello.ts了[doge]

下面我列举了一些比较常用的tsconfig.json的配置信息,大家可以根据自己需要进行配置,也可以查看官网文档,点进官方文档之前记得给本篇文章点个赞支持一下哦,别过去了就回不来了😚;

{
  /*
  配置文件,根据该配置进行编译
  "include": []-->哪些配置文件需要被编译
  '*'表示任意文件
  '**'表示任意目录
  */
  "include": [
    "*"
, "src/*"  ],
  // 不包含
  "exclude": [
  ],
  // "extends": "" --> 继承于某个配置文件
  // "files": [?] //文件,不能是目录
  "compilerOptions": {
    // 编译为ES的版本
    "target": "ES3",
    // 指定要使用的模块化方案
    "module": "es2015",
    // "lib": []-->指定项目中需要用到的库-->一般不需要设置
    "outDir": "./dist",  //编译后的存放目录
    // 将代码合并到为一个文件-->如果和ing多个模块,module-->system|amd
    // "outFile": "./dist/app.js"
    // 是否对js文件进行编译
    "allowJs": false,
    // 是否检查js代码符合规范
    "checkJs": false,
    // 是否移除注释
    "removeComments": false,
    // 不生成编译后的文件
    "noEmit": false,
    // 当有错误的时候就不生成编译后的文件
    "noEmitOnError": false,
    // 所有严格模式的总开关
    "strict": false,
    // 严格模式-->性能更好
    "alwaysStrict": true,
    // 不允许隐式的any类型
    "noImplicitAny": true,
    // 不允许不明确类型的this
    "noImplicitThis": true,
    /*
    function fn(this: window){
      alert(this)
    }
    */
    // 严格地检查空值-->比如某些获取dom元素
    "strictNullChecks": false
  }
}


然后记得终端输入下方命令就可以对整个项目中的多个文件进行编译和监控了

tsc -w


到这里,你已经跨出了学习TS中最难的一步了,接下来面对你的将是康庄大道=======>success

当然还有其他方式来控制整个项目对TS的编译方式,比如在webpack中的配置可能是这样的(这里就不过多赘述了,大家初始学习的话可以跳过这方面的知识,明白前两种编译方式就可以应对接下来的知识,后续你在编写大型项目中根据自己的需求再在网上找对应的配置就可以,毕竟知识的海洋是无限的,有些东西需要深入了解,但有些东西又得不求甚解,很多时候做一样东西你不一定会其中的技术栈,然后你再学-->使用,技术是学不完的,按需学习感觉才是这个时代的主流,当然,程序员的核心素质除外,这个挖再深都对你好处很大):


// tsconfig.json中
{
  "compilerOptions": {
    "module": "ES2015",
    "target": "ES2015",
    "strict": true
  }
}


// package.json中
{
  "devDependencies": {
    "ts-loader": "^9.2.6",
    "typescript": "^4.5.2",
    "webpack": "^5.65.0",
    "webpack-cli": "^4.9.1"
  },
  "scripts": {
    "build": "webpack"
  }
}


// webpack.config.js中
// 引入一个拼接路径的包
const path = require('path');
// webpack中所有的配置信息
module.exports = {
  // 入口文件
  entry: "./src/index.ts",
  // 指定输出文件所在目录
  output: {
    // 指定目录
    path: path.resolve(__dirname, 'dist'),
    // 打包以后的文件名
    filename: "bundle.js"
  },
  // 指定webpack打包时要使用的模块
  module:{
    // 指定加载的规则
    rules: [{
      // test指定的是规则生效的文件
      test: /.ts$/,
      // 要使用的loader
      use: 'ts-loader',
      exclude:/node-modules/
    }]
  }
}


好了,刚才突然就想感叹一下,接下来我们一起走这条康庄大道吧

认识类型


类型是typescript中最重要的概念,毕竟人家就叫typescript

TS中是如何声明一个类型的呢?记住下面的格式:

let a: number;


上面的代码又和我们平常书写的JS有什么不同的?

JS中,我们输入如下的代码,不会报错:

let a;
a = 'this is string';
a = 1234;
a = true;

但是在TS中,不同类型的值是不能相互赋值的,否则将会报错,这个报错也是我们选择TS的重要原因,JS是动态类型语言,很多时候你都不会发现你的类型搞错了,编译器也不会给你报错,当这个错误影响到项目运行的时候,你又找不到,昂~

在初入计算机领域时,我们最怕的就是编写的代码被编译器提示报错,但是现在,我们更怕的是生产环境中报错,编译器最好多报一点错,因为编译器的提示真的太好解决了,就像你的坐姿,在小时候写字的时候是最好纠正的,但现在,害>程序员的腰酸背痛!

下方的代码中,编译器会提示报错:

let a: number;
// a = 'hello' --> 报错


let b: string;
b = "hello";  // 这样才行


当然你也可以这样let a: any;,然后你也可以像JS那样赋值,千万不要这么做,除非万不得已,否则就违背了TS的初衷,对了,如果声明对象不指定类型let a;也会导致隐式的any类型,永远记得不要这么做🈲

除此之外,你也可以给函数的形参和返回值做类型的声明:

function sum_ts(a:number, b:number):number {
    return a + b;
}


回想一下,js中的函数是不考虑参数的类型以及个数的,它的个数只是表面的个数,就算你不声明形参个数,你仍然可以给JS的函数传任意的参数个数,毕竟JS函数可以使用**arguments** 这个类数组对象进行访问,这就导致很多时候你想编写一个万用的函数,需要考虑到是否收集剩余参数,而其他开发者在使用这个函数的时候也不能很清楚的知道这个函数的输入输出,这就完全违背了封装的思想-->拿来就用!

所以,好好学一下TS吧~ ( ^_^ )

深入类型


基本类型介绍

就是JS中的八种类型,你还记得吗?

😀面试官: 说一说ES6中的八种数据类型?

❓我: JavaScript共有八种数据类型,分别是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。

😀面试官: 哪两种类型是新增的?说一说你对它们的了解?

❓我: 其中 Symbol 和 BigInt 是ES6 中新增的数据类型:

  • Symbol 代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题,可以很好地隔离用户数据与程序状态。
  • BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围。

TS中的基础类型也是这八种,写成TS的格式的话就是如下代码:

let str: string = "justin3go";
let num: number = 20;
let bool: boolean = false;
let u: undefined = undefined;
let n: null = null;
let obj: object = {justin: 3};
let big: bigint = 100n;
let sym: symbol = Symbol("justin3go"); 


TS难吗,不难,难的是JS!

当然还有一些需要注意的地方,下面将详细阐述:

  1. 使用字面量形式进行类型声明:
let a1: 10;
a1 = 10;
// a1 = 20 --> 报错
// 作用:
let b1: "male" | "female";   // 这样b1就只能在这两个字符串中选了
// 记得:现在做的限制是对以后的回馈,后续写代码才会更加的方便。
//--------------------------分界线--------------------------------------
// 联合类型
let c1: boolean | string;


关于TS中的任意类型:

// any-->和js一样关闭类型检测
let d1: any;
// 注:声明变量如果不指定类型,默认为隐式的any
let e1;
// 赋值
let s1: string;
//any可以赋值给任意类型,同时导致s1也变为any类型了
s1 = d1;


// 但是unknown就不一样-->实际上就是一个类型安全的any,不能直接赋值给其他的变量
let g1: unknown;
g1 = 10;
g1 = true;
g1 = "hello";
// s1 = g1 --> 此时g1赋值会报错,不能赋值
if (typeof g1 === "string") {
    s1 = g1; //这种就不会报错
}
//--------------------------分界线----------------------------------
// 当你确认g1就是字符串,一定要赋值的话,可以这么做:
// 类型断言-->我知道它就是字符串
s1 = g1 as string;
s1 = <string>g1;


关于函数中的空值:

// 空值
function fn1(): void {
    // return 123 报错
    return;  // 对
}
// 没有值-->表示永远不会返回结果,空也不返回(return;也不行)
function fn2(): never {
    //作用:可以用来指定专门的函数报错 
    throw new Error("error");
}


对象类型介绍

定义对象的结构

刚才,我们一起学习了八种基本类型,其中有一种叫做let obj: object;,我们可以对其这样赋值:

// let obj: object;
obj = {};
obj = function () {};


所以一般也不会使用object,因为js中一切都是对象,相当于没有限制,一般这样使用,主要是声明里面的属性,之后使用结构就必须一摸一样:

let b2: { name: string };
// b2 = {} --> 这种就会报错:因为需要且仅需要一个name属性
// b2 = {name: "孙悟空", age: 18}  -->error
b2 = { name: "孙悟空" };


但是,偶尔我们也许需要部分结构是固定的,还有一些key值不确定,这时候,我们可以使用来实现这种表示:

// ?代表这个属性有和没有都是可以的
let c2: { name: string; age?: number };  


如果需要需要name这一个属性,其他的属性无所谓,我们可以这么做:

let d2: { name: string; [propName: string]: any };  // 代表必须包含name属性就可以了
d2 = { name: "猪八戒", xixi: "xixi", haha: "haha" };

既然对象可以提前定义其结构,那么理所当然函数也是可以提前定义其结构以及返回值的

限制函数结构的语法:

let e2: (a: number, b: number) => number;


数组

  1. 我们可以使用string[]来表示字符串数组;
let l2: string[];
l2 = ["a", "b", "c"];


还可以使用Array<string>来表示

let i2: Array<string>;


元组

元组:相当于固定长度的数组-->效率比较高

let h: [string, string];
h = ["haha", "xixi"];


枚举

enum Gender {
    Male,
    Feamle,
}
let j2: { name: string; gender: Gender };
j2 = {
    name: "悟空",
    gender: Gender.Feamle,
}


学一样东西必不可少的就是提问,新技术的出现必定是为了解决某一类问题,带有一定目的的,所以这种类型有什么好处吗?

其实上面的例子已经解释得非常清楚了,就是让某些标识符有语义。怎么理解这句话呢,比如如果没有该类型,我们表示男女一般会使用01来表示,那到底0是男还是1是男呢,当然01都可能是男/(ㄒoㄒ)/~~

开个玩笑,所以枚举就是为了解决这类问题的,它让我们在编程的时候更加方便地知道性别这个类包含哪种类型,简单来说是下面几点:

  • 实际上这个值在转的时候就会转为0,1
  • 与直接0,1比较更容易辨识
  • 与直接字符串比较更节约存储

然后,再补充一些小知识:

// & 表示且
let g: { name: string } & { age: number };
// g = {name: "悟空"} --> 报错


// 类型的别名
type myType = 1 | 2 | 3 | 4 | 5;
let k2: myType;
let h2: myType;


到这里,你几乎已经完成TS学习的一半了,是不是非常简单,接下来的内容如何小伙伴接触过java、C++这种面向对象的语言,可能理解起来非常简单,接下来的知识就是TS中另外一个非常重要的概念


当然,如果你熟悉JS中类的语法,对于接下来的理解也会非常简单

简介

还是和之前hello world一样,我们先来手写定义一个类,然后实例化这个类,认识一下它,一回生,二回熟嘛,知识也是这样的:

// 使用class定义
class Person {
  // 实例属性
  name: string = "孙悟空";
  // 只读属性
  readonly gender:boolean = true;
  // 在属性前使用static关键字可以定义类属性(静态属性)
  static age: number = 18;
  sayHello(params:string):void {
    console.log('Hello!',params)
  }
}


const per = new Person();
console.log(per.name);  //通过实例访问(duxier)
console.log(Person.age);  //通过对象名访问


构造函数

这部分也可以说和JS中ES6语法的构造函数一模一样:

class Dog {
    name: string;
    age: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    bark() {
        alert("汪汪汪!");
    }
}


继承

也是差不多的:

class animal {
    name: string;
    age: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    sayHello() {
        console.log("动物在叫~");
    }
}
//共有的代码写在父类之中
class Dog extends animal {
    run(){
        console.log("旺仔再跑");
    }
}
class Cat extends animal {}


后继承都来了,super关键字自然不会缺席

    class Animal {
        name: string;
        age: number;
        constructor(name: string, age: number) {
            this.age = age;
            this.name = name;
        }
        sayHello() {
            console.log("动物在叫~");
        }
    }
    class Dog extends Animal {
        sayHello(): void {
      //调用父类的方法
            super.sayHello();
        }
    }
  // 用在添加属性后构造函数中
  class Cat extends Animal {
    color:string;
    constructor(name:string, age:number, color:string){
      super(name, age)
      this.color = color
    }
  }


当然,super再在JS中是有一些限制的,这里默认是认为你们已经熟悉了JS了,还没熟悉的赶快去熟悉,来学什么TS呢?[推荐阅读红宝书的p260]

抽象类

再回想一下,JS中有抽象类吗?没有。能实现抽象类吗?可以:通过new.target的判断来判断是非常容易实现的:

javascript


class animal {
  constructor(){
    console.log(new.target);  // 表示new关键字后面跟着的类型
    if(new.target === animal){
      throw new Error('xx不能被实例化')
    }
  }
}


此时,你就不能直接实例化这个类了,只能通过继承,然后实例化其子类是没有问题的。

到这里,你可能会说别人其他语言都有abstract关键字使用,为什么我JS还要自己手动判断呢?似乎一点也不优雅!

于是TS中引入了abstract关键字,可以非常方便地帮助我们定义抽象基类:

除此之外,在JS中定义抽象方法也需要在构造器中多增加一个判断--this下是否有某方法,没有就抛出异常,而这里TS的abstract关键字也可以使用在抽象方法上,非常方便


  // 不能用来创建对象,这个类就是用来被别人继承的
  // 抽象类中可以去添加抽象方法
  abstract class animal{  // 1
    name: string;
    constructor(name:string){
      this.name = name
    }
    abstract sayHello():void;  // 2
  }


接口

type myType = {
    name: string;
    age: number;
};
//接口就是用来定义一个类结构的
// 可以当作类型声明去使用
// 区别是重新再写一个myInterface不会报错,结果是合并
interface myInterface {
    name: string;
    age: number;
}
// 接口可以在定义类的时候限制结构
// 接口中所有的属性都不能有实际的值
// 接口只定义对象的结构而不考虑实际值
// 所有的方法都是抽象方法
// 去实现一个接口
class Mycalss implements myInterface {
    name: string;
    age: number;
    constructor(name: string, age: number) {
        this.age = age;
        this.name = name;
    }
}


属性的封装

再想一下,我们实现一个私有变量有多麻烦,用闭包实现仅在内部作用域能访问该变量,即私有化,然后再使用weakmap解决闭包导致的垃圾回收的问题,当然ES6中的#也可以非常方便的添加私有变量,而这里TS中的private似乎更符合我们在其他语言中见识的一致。


//属性可以任意修改将会导致对象中的数据变得非常不安全
class Person {
    // pubulic默认值,可以在任何地方修改
    // private:只能在内部修改,当前类,子类也不行
    // protected: 只能在当前类和当前类的子类中使用
    public _name: string;
private _age: number;
constructor(name:string, age:number){
    this._name = name;
    this._age = age;
}
// getName(){
//   return this.name
// }
// setName(value:string){
//   this.name = value
// }
//ts中设置getter方法的方式
get name(){
    return this._name
}
}
// 其他地方就可以这样调用name属性
const per= new Person("1",1)
console.log(per.name);


最后,在补充一个泛型的概念,这个就和C++中的泛型几乎一致,就是写函数时可以不定参数的类型,使用函数时在确定参数的类型:

C++中是这样的vector<int> test:向量中存储的类型是int,vector<string> test:向量中存储的类型是string

TS中是这样使用的:


// 在定义函数或者是类时,如果遇到类型不明确就可以使用泛型
function fn<T>(a: T): T{
  return a;
}
//这样可以避免使用any,同时保证我的参数以及返回值的类型时相同的
//使用
//可以直接使用具有泛型的函数
fn(10);
//指定泛型
fn<string>('hello')


最后最后,写作不易,支持一下哦~

\

目录
相关文章
|
4月前
|
人工智能 JavaScript Shell
AgentRun实践指南:Agent 的宝藏工具—All-In-One Sandbox
AgentRun 推出 All-In-One Sandbox(AIO),一体化集成浏览器、Shell 与代码执行环境,统一文件系统、零配置云上运行。启动快(5秒)、文件访问毫秒级、内存减半,完美支持多步骤自动化、LLM Agent 及人机协同任务。
|
NoSQL Linux 网络安全
Linux命令汇总
Linux命令汇总
1274 0
|
6月前
|
存储 运维 NoSQL
Agentic RAG:用LangGraph打造会自动修正检索错误的 RAG 系统
本文介绍基于 LangGraph 与 Redis 构建生产级 Agentic RAG 系统,通过引入智能体机制实现检索结果的自动评估与查询重写,解决传统 RAG 回答偏离问题。系统具备自校正、决策透明与模块化优势,显著提升复杂场景下的问答准确率。
487 4
Agentic RAG:用LangGraph打造会自动修正检索错误的 RAG 系统
|
6月前
|
人工智能 算法 搜索推荐
马斯克2026采访详解:中国AI算力将远超世界,世界变化的奇点即将到来!
2026年1月,马斯克在德州工厂预言:AGI将于2025-2026年实现,Optimus机器人3年内超越外科医生,中国发电量将达美国3倍,AI算力将领先全球。他称“奇点已来”,电力决定AI未来,太阳能是关键。
|
存储 安全 Linux
服务器数据恢复—如何预防服务器故障?服务器发生故障如何恢复数据?
服务器常见故障: 硬件故障:磁盘损坏、电池故障等。 软件问题:操作系统崩溃、未知的程序运行错误等。 病毒破坏:勒索病毒加密、删除服务器数据等。 不可控力量;服务器浸水、火烧、机房倒塌等导致服务器损坏和数据丢失。 误操作:工作人员操作失误导致数据丢失,如格式化、删除、覆盖等。
674 16
服务器数据恢复—如何预防服务器故障?服务器发生故障如何恢复数据?
|
11月前
|
人工智能 JSON 监控
电商 API 赋能,多平台促销活动精准同步
在电商多平台促销中,手动管理易导致价格混乱、库存超卖等问题。电商 API 通过自动化实现促销活动的精准同步,提升效率、减少错误,助力企业高效运营,实现销售增长与成本节约,是电商数字化转型的关键工具。
|
机器学习/深度学习 搜索推荐 语音技术
前沿探索:融合语音克隆与TTS技术实现个性化语音助手
【10月更文挑战第20天】随着人工智能技术的迅猛发展,语音助手已经成为我们日常生活不可或缺的一部分。然而,传统的语音助手往往缺乏个性化元素,无法充分满足用户的独特需求。作为技术专家或研究人员,我一直致力于探索如何将语音克隆(Voice Cloning)技术与文本到语音(Text-to-Speech, TTS)技术相结合,创造出更加个性化且自然流畅的语音助手。本文将分享我的研究成果和个人观点,希望能为这一领域的未来发展提供一些启示。
803 2
前沿探索:融合语音克隆与TTS技术实现个性化语音助手
|
存储 弹性计算 固态存储
阿里云服务器按月租用价格是多少,月付收费标准与活动价格参考
阿里云服务器月付租用价格是多少?阿里云服务器既可以月租也可以按年租用,按月可选的时长有1个月到10个月,通常选择较多的是1个月、3个月、6个月时长,目前按月租用价格有经济型e实例4核16G配置10M带宽100G ESSD Entry云盘,月租优惠价70元1个月、210元3个月,如果选择8核32G配置的月付优惠价是160元1个月、480元3个月。本文将详细介绍阿里云服务器的月付收费标准及当前活动价格,帮助您更好地了解在阿里云服务器月付租用价格情况。
|
SQL 搜索推荐 数据库
Sql中的like的用法
Sql中的like的用法
1282 0
|
人工智能
写歌词的技巧和方法:构建独特歌词结构的策略,妙笔生词AI智能写歌词软件
歌词创作如同搭建艺术殿堂,独特的歌词结构是其基石。掌握构建策略,让你的歌词脱颖而出。开头营造神秘氛围或出人意料的情感,主体部分采用倒叙、插叙或融合矛盾情感,结尾带来情感反转或深邃思考。《妙笔生词智能写歌词软件》提供 AI 智能写词、押韵优化等功能,助你轻松获取灵感,打造独特歌词结构。

热门文章

最新文章