【typescript】写给JS老鸟的TS速成教程-成都快上网建站

【typescript】写给JS老鸟的TS速成教程

写给JS老鸟的TS速成教程

成都创新互联于2013年成立,是专业互联网技术服务公司,拥有项目成都做网站、成都网站建设网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元古浪做网站,已为上家服务,为古浪各地企业和个人服务,联系电话:18980820575

搭建基础开发环境

要准备的环境

node.js 14.14以上 ,vs code最新,vs code TS开发插件

开始开发

方式一:TS原生编译开发

补充知识:i是install的简写,-g是global的简写,除此外还有-D = --save-dev 、-S= --save,现在新版npm cli好像会默认执行—save

npm i -g typescript && tsc -init

vs code创建 文件夹/index.ts,

手动编译 tsc+文件名,改一次编译一次

自动编译 Ctrl+shift+B —> 监视模式,文件变动时自动编译 或 如下:

① tsc 文件名 -w,缺点是只能监视一个文件,除非开多个命令行。

② 创建tsconfig.json,只写一对{},使其符合json规范,然后直接执行 tsc,即可监视所有ts文件的改动。

运行结果:创建index.html, script.import 编译好的index.js,用浏览器打开index.html

开箱即用见 附件【TS_ori】

编译控制

tsconfig.json是ts编译器的配置文件,可以对编译进行自定义

不知道可选值可以先给一个错误的值,编译器会列出所有可选的正确配置值

tsconfig.json可以写注释,因为其是ts编译器的配置文件。

{

// 初步

"include":[ //指定哪些目录的ts文件需要被编译,包含目录

"./src/**/*" //.当前目录 src文件夹 **任意目录 *任意文件

],

"exclude":[],//指定哪些ts文件不被编译,排除目录,有默认值,比如node_modules

"extends":"./config/base",//继承某个配置文件,配置复用

"files":[],//指定ts文件编译,包含文件,与include类似

//进阶

"compilerOptions":{

"target":"ES6", //指定ts编译成何种js版本,即目标代码的版本

//ES2015(ES6),ES2016...ESNext(最新版ES)

"module":"ES6",//指定模块化解决方案

"lib":["dom"],//用来指定项目中使用到的库,一般不写此属性(有默认值),除非代码在nodejs中运行,缺少某些库,如dom。dom库为document

"outDir":"./dist",//指定编译后文件所在目录。dist即distribution,发行版

"outFile":"./dis/app.js",//将代码合并为一个文件,若需要把各模块合并为一个文件,只能支持amd and system模块方案

"allowJs":false, //是否对js进行编译,默认否 - false //合并文件一般不用outFile,而是结合打包工具来实现

"checkJs":false, //是否检查js代码是否符合语法规范

"removeCommentss":true,//是否移除注释

"noEmit":false,//执行编译但是不生成编译后的文件,场景是只用到ts编码和类型检查, 不须编译

"noEmitOnError":false,//发送错误时不生成编后的译文件,默认为false,为的是让js程序员缓慢过渡到ts,建议改为true

"strict":false,//以下三个检查的总开关,建议开发时设为true

"alwaysStrict":false,//指定编译后的js文件是否使用严格模式。严格模式:语法严格,在browser性能好一些

"noImplicitAny":false,//Implicit隐式的,开启隐式any的检查,不允许使用

"noImplicitThis":false,//不允许不明确类型的this

"strictNullChecks":false,//严格检查空值,若一个变量可能为null,则报错,除非先进行非空判断或box?.addEventListener()

}

}

方式二:自动化开发

补充知识:webpack-cli是通过命令行来使用webpack、ts-loader是webpack加载器,是ts和webpack的桥梁

补充知识:webpack这东西就是会沿着你给定的一个入口文件去遍历所有关联的文件,然后按照一定规则重新整理、压缩成新的一批文件,我们的文件格式是无穷无尽的,webpack不可能认识和处理全部格式,所以我们通过加入各种loader,称加载器,来帮助webpack认识它们。

创建空文件夹,执行npm init -y(完成项目初始化)

npm i -D webpack webpack-cli typescript ts-loader

撰写webpack配置。要注意的是,webpack打包必须配合tsconfig.json使用,也就是你的ts代码处要有这个tsconfig.json文件,因为ts程序的具体编译的工作还是由ts本身提供,而ts编译本身要用到tsconfig.json,现在看来,ts-loader真的仅仅是个桥梁。

在package.json中加入打包命令build:webpack,执行npm run build。

撰写配置

使用chrome来查看ts程序的运行结果

补充知识:webpack可以支持自动生成html文件并引入打包好的资源,以演示代码效果,这比自己手动写个html方便多了,生成这个html文件有两种方式,配置式,如传个title参数,其他由webpack自己决定,或者自己拟定一个html模板交给插件。

cnpm i -D html-webpack-plugin

自动化构建--所写即所见

cnpm i -D webpack-dev-server ,package.json 加入 "start":"webpack serve --open" ,npm run start

清楚旧的打包文件

打包默认模式是用新文件覆盖旧文件,可能存在残留问题,解决方法:clean-webpack-plugin

指定可引入的文件

指定哪些文件可以被其他文件作为模块来引入,这里的引入是代码文件之间的引入,这样我们就可以愉快地使用ESM(ES Module)了

解决目标代码的兼容性问题

补充知识:前端常见兼容性问题有两种,一种是浏览器内核类,一种是规范版本类。前者主要表现为在Chrome能运行的代码,在Firefox却出现问题,在iPhone默认浏览器能运行的代码在华为默认浏览器却有问题;后者主要表现为ES6的代码在浏览器中报错,因为ES6对比ES5变化是较大的,现在ES规范每年一个版本,浏览器跟进也比以前快了,这个问题正变得越来越不是问题。

TS的tsc仅仅能够实现把ts源码编译成不同ES规范版本的js代码而已。

babel/core是babel的核心库、present-env是预置环境,预置不同浏览器环境,帮助代码兼容不同浏览器,babel-loader是结合webpack和babel的桥梁、core-js(Modular standard library)可以使老版本的浏览器使用到新版本的js的一些技术,如promises等,由于这个库比较庞大,内含很多小库,且是模块化的,我们应按需使用,按需使用我们直接通过webpack来实现

webpack rules的use执行顺序是从下往上执行,我们先用ts-loader把ts转换为js,然后用babel-loader把新版本的js转换为老版本/兼容性高的js

  1. cnpm i -D @babel/core @babel/preset-env babel-loader core-js

关于兼容性打包后仍报错

补充知识:设置了targets.ie==11后,打包的代码拿到ie11运行依然报错,原因在于webpack打包后的代码用了一个箭头函数实现的自执行函数包裹,作用是创造一个代码作用域,防止全局变量污染等,它实际是webpack自动生成的,与babel无关,babel只能源文件内的箭头函数起作用,实际上,这可能是webpack故意为之,其本身就是不想兼容某些低版本浏览器,解决方法,out加上environment:{arrowFunction:false},取消箭头函数。

TS语言

报错信息,assign:赋值、指派、指定,resolve:解析、决定、解决

默认ts代码有错误,仍然可以编译生成js,在tsconfig中可更改

ts可编译成任意版本js

若赋初值,ts会根据值类型推算变量类型,这会使变量声明加上类型变得多此一举,没错,实际上,类型检测更多是用给函数传参(形参)和返回值的。

类型

补充知识:可用字面量代替类型名,如10,以后只能赋值10,有点常量的意思。除此之外,还有联合类型、任意类型等

talk is cheap,show me the code

export const zex: number = 1;

{

let a: number = 10;

let b: number = 20;

console.log(a, b)

//计算变量类型

let c = true;

//计算函数返回值类型

function sum(a: number, b: number): string {

return a + b + "";

}

let result = sum(a, b);

}

const zex:number=1;

{

// 字面量赋值

let a:10;

let a1:number;

let b:10=10;

a=10;

a1=10;

// 用 或符号 构成 联合类型

let c:"male"|"female";

c="male";

c="female";

let d:string|number;

d=10;

d="hello";

// 任意类型 - 关闭类型检测

let e:any;

e=10;

e="female";

e=true;

// 隐式any

let f;

f=10;

f="female";

f=true;

// 赋值

// 以下不报错,这导致a的类型检测失效

a1=e;

// unknown同any差不多,但是可解决以上问题,是一个类型安全的any

let g:unknown;

// a=g;报错,应改为

if(typeof g == "number"){

a1=g;

}

//断言:判断的语言,根据实际情况,把某个变量人为(自己)地断定为某种类型,跳过编译

a1 = g as number;

a1 = g;

//函数的返回值

//返回值为number|string型

function sum(a:number,b:number){

if(a>b){

return a+b;

}else{

return a+b+"";

}

}

function sum2(a:number,b:number):number|string{

if(a>b){

return a+b;

}else{

return a+b+"";

}

}

// 空返回

function sum3(a:number,b:number):void{

return;

}

function sum4(a:number,b:number):void{}

function sum5(a:number,b:number):void{

return undefined;

}

// never:永远不会返回结果

// 没有返回值也是一种返回值,而never是空空

// 在程序报错时,代码立即停止执行,程序结束,函数结束,所以永远不会有值返回,事情不会发生

function err():never{

throw new Error("err");

}

}

{

// object其实是无用的,因为ts一且皆对象,并没有起到类型限制的作用

let a:object;

a={};

a=function(){};

//以下有效

let b:{name:string};

b={name:"John"};

// b={name:"John",age:12}结构不一致报错

// ?-可选属性

let c:{name:string,age?:number};

c={name:"John",age:12};

c={name:"John"}

// 任意属性:自由添加属性,新属性未知

// 新属性名为字符串,属性值为任意类型,propName命名随意

let d:{name:string,[propName:string]:any}

d={name:"John",str:123}

let d1:{name:string,[propName:string|number]:any}

d1={name:"John",str:123}

d1={name:"John",123:123}

// 限制函数,单Function无意义

let e:(a:number,b:number)=>number

// 数组

let f:string[];

f=["John"]

let f1:Array;

f1=[123];

// 元组:固定长度的数组

let g:[String,String];

// 必须符合给定,不多不少

g=["Hello","Hello"];

//考虑数据存储与表示分离,数据库存储应简短、非字符串,此时Object并不满足要求

// 枚举,默认从0开始

enum Gender{

male=0,

female=1

};

let h:{name:string,gender:Gender};

h={name:"Jhon",gender:Gender.female};

console.log(h.gender,h.gender==Gender.female)

// & - 与,类型组合

let i:number&string //无意义

let i1:{name:string}&{age:number};

i1={name:"John",age:18};

// 类型的复用-别名

let j1:number;

let j2:1|2|3|4|5;

let j3:1|2|3|4|5|6;

type myType=number;

type myType2=1|2|3|4|5;

let k1:myType;

let k2:myType2;

let k3:myType2|6;

k3=3

k3=6

// k3=7 报错

}

// 类

class Person {

// 实例属性,通过实例访问

readonly name: string = "默认名字";

age: number = 18;

// 类属性,通过类访问

static avgAge: number = 18;

//只读属性

static readonly baseName: string = "张"

// 类方法

sayHello(name: string): string {

return "Hello";

}

static sayHi(name: string): string {

return "Hi";

}

};

const per = new Person();

Person.avgAge = 19;

per.age = 20;

// Person.name="三三"; // 报错

// Person.baseName="李"; // 报错

console.log(Person.avgAge, per.age);



// 构造器与this

class Dog {

name: string;

age: number;

constructor(name: string, age: number) {

// this表示当前实例

this.name = name;

this.age = age;

}

bark() {

// 当前调用方法的对象,如dog1.bark(),this为dog1

console.log(this, "旺旺旺");

}

}

const dog: Dog = new Dog("旺财", 3);

// 继承

{

class Animal {

name: string;

age: number;

constructor(name: string, age: number) {

this.name = name;

this.age = age;

}

bark() {

}

}

class Dog extends Animal {

bark() {

console.log(this.name + this.age + "旺旺旺");

}

run() {

console.log("蹦蹦跳跳");

}

}

class Cat extends Animal {

sex: string;

constructor(name: string, age: number, sex: string) {

// 调用父类构造器

super(name, age);

this.sex = sex;

}

bark() {

// 引用父类的方法

super.bark();

}

}

const cat = new Cat("小喵", 3, "母");

//抽象类

//对于某些类,由于本身拿来实例化是不合适的,且我们也不希望被这样做

//因此我们就把他设为抽象类,只可以继承,不可以实例化

abstract class Food {

name: string;

color: string;

// 抽象类须有构造器

constructor(name: string, color: string) {

this.name = name;

this.color = color;

}

abstract eat(name: string): void;

abstract cook(name: string): number | string;

}

/**

* 在限制对象的类型上,以下两种方式功能一致

* 接口,定义了类的结构(属性、方法)

* 此接口非彼接口,它与Java的接口有点不同

*/

type myType = {

name: string,

age: number

};

interface myInterface {

name: string;

age: number;

}

// 接口可以重复定义,实际效果是同名接口的总和

interface myInterface {

sex: string;

}

const man: myInterface = {

name: "张三",

age: 18,

sex: "男"

}

// 限制类的结构

interface myInterface2 {

name: string;

sayHi(): void;

}

interface myInterface3 { }

class People implements myInterface2, myInterface3 {

name: string;

constructor(name: string) {

this.name = name;

}

sayHi(): void {

console.log(this.name);

}

}

/**

* 抽象类和接口

* 抽象类:

* 1、可以普通方法,也可以抽象方法

* 2、通过继承来使用,TS 类的设计为单继承

*

* 接口:

* 1、只有抽象方法

* 2、通过实现来使用,支持多继承

*/

}

// 属性的封装 - 保护类的属性

// 属性可被随意修改将导致对象中的数据变得不安全

// 通过类修饰符解决这个问题

// 默认为public,属性可被随意修改

{

class Person {

name: string;

public sex: string;

public age: number;

constructor(name: string, sex: string, age: number) {

this.name = name;

this.sex = sex;

this.age = age;

}

}

// 最强安全性

// private修饰的属性,只有两种修改方式:

// 1、构造器传入

// 2、调用实例方法修改,这种方法在java中被称为setter

// 此外,这种方式也给属性的访问带来麻烦,我们同样只能通过方法return该属性来访问,在java中称为getter

// 这种setter和getter模式在C#中被吸收为语法:

/**

* get{

return _name;

}

set{

_name = value;

}

*/

class Person2 {

private name: string;

private sex: string;

private age: number;

protected height: number;

constructor(name: string, sex: string, age: number, height: number) {

this.name = name;

this.sex = sex;

this.age = age;

this.height = height;

}

setName(name: string): void {

this.name = name;

}

getName(): string {

return this.name;

}

}

// 此外,private属性也不可以被子类访问,protected可以

class Person3 extends Person2 {

showName(): void {

// 无法访问name,可以访问height

// console.log(this.name);

console.log(this.height);

}

}

// 泛型

// 当一种类型是什么要在实际中才能确定是,我们使用泛型

// 泛型就是类型的抽象表示(代表)

// 当以下函数的参数与返回值类型一致,但是无法确定是什么具体类型时,用泛型

function fn(a: number): number {

return a;

}

// 能否使用any?不行,一是关掉了类型检查,这将埋下隐患,二是无法体现两者类型一致

function fn2(a: T): T {

return a;

}

function fn3(a: T, b: K, c: I): T {

return a;

}

function fn4(a: T, b: K, c: number): number {

return c;

}

// 在调用含泛型函数时,一般会自动推定泛型的类型,我们也可手动指定

fn2(1);

fn4(1, "2", 3);

fn4(1, "2", 3);

}

【附件】

https://github.com/heytheww/TSLenrning


分享文章:【typescript】写给JS老鸟的TS速成教程
链接分享:http://kswjz.com/article/dsojhij.html
扫二维码与项目经理沟通

我们在微信上24小时期待你的声音

解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流