您现在的位置是:首页 >技术交流 >typescript网站首页技术交流
typescript
1 引入
1.1 介绍
javascript变量的特点是变量类型是可变的,这是一个很好的特性,但是如果你在之前写了一个处理两个数字的函数,之后你忘记了里面只能用数字,你传了字符串进去,但是js不会报错,这使得debug麻烦起来
所以typescript在js的基础上进行了扩展,限制了一些东西,ts使得书写更复杂,但是更规范起来,而且也有了更加完善的报错信息。
ts能够兼容所有的js语法,所以你可以完全用js的语法也没有问题
1.2 配置环境
需要先安装nodejs,然后用npm安装typescript
npm i -g typescript
然后你创建一个ts文件,写一个普通的console.log
然后像使用javac一样使用tsc 文件
来编译它,注意找准路径
这个时候就编译成js文件了。
这个时候有一个特点,如果你ts文件即使有ts的语法错误,tsc依旧能够编译成功。后面能够修改成有错不能编译成功。
2 类型声明
数据类型
ts的数据类型有number string boolean 字面量 any unknown void never object array tuple enum
声明
比如声明一个number类型
let a:number
如果你变量类型用错了,就会报错。
字面量类型
字面量就是一个确切的值
let a:10
这个时候a就只能是10
这种写法比较少见
联合声明
可以用|来放宽限制
let a:"male"|"female";
let b:boolean|number;
any类型
any就是所有类型,在ts中要避免使用这种情况,所有的let就相当于隐式的any
unknown类型
unknown是一个安全类型的any
如果是any,下面的代码可以成功,最后的结果是a也变成了any类型的,a的类型被改变了,ts的类型判断就没有意义了。
let b:any = 51;
let a:string;
a = b;
所以对于我们还不知道类型是什么的变量,可以先用unknown来声明
下面的代码会提示你b的变量未知,不能复制给string类型的a
let b:unknown=51;
let a:string;
a=b;
所以这个时候有三种方式来断言b是string类型的。
a = b as string;
if(typeof b === string){
a = b;
}
a = <string>b;
暂时觉得第二种更加安全.
void类型
与c的函数一样,就是没有返回类型
object类型
如果直接声明一个object类型的也没有意义,万物皆对象
可以这样设置
let a:{name: string}//
let a:{name:string, age?:number}//可选属性
let c:{name:string, [propName:string]: number}//声明后面的number类型属性
let f:(a:number, b:number)=>number;//f是一个函数对象,声明了形参类型和返回类型的
数组类型
let a:string[]
let b:number[]
let c:Array<number>;
元组
元组是固定长度的数组,性能比可变长度的数组要好
let h:[string, number];
h = ["hello", 123];
enum枚举
这是ts中新增的类型
enum Gender{Male, Female};//这里对应的值是多少不重要了,有点像是map
let i:{name: string, gender:Gender};
i = {name:"xxx", gender:Gender.Male}
console.log(i.gender === Gender.Male);
类型别名
type myType = 1|2|3|4
let k:myType;
函数声明
下面的函数就能声明参数类型和返回类型
function sum(a:number, b:number):number{
return a+b;
}
隐式声明
a这个时候会直接被解析成bool类型
let a = false;
3 编译选项
3.1 编译多个文件
watch监视模式
每次ts修改想要得到编译后的js需要每次使用tsc命令
可以用tsc app.ts -w
开启监视模式,每次修改的时候都会自动编译了。
但是当文件多的时候很麻烦。
tsconfig.json引入
所以我们需要一个类似c里面makefile的文件来设置编译规则,让它自动编译所有的文件,并且可以设置编译成哪个版本的js,es3还是es5还是es6
先在底下创建一个tsconfig.json的文件,就可以在里面设置编译规则。
就算这个时候你json文件里面什么都不写,只写一个json的大括号,然后使用tsc,也能自动编译同目录下所有的ts文件,以及同目录下子文件ts
include
tsconfig是默认编译根目录下所有的ts文件,include是指定要编译的文件。
指定编译src底下的所有ts文件
{
"include": [
"./src/**/*"
]
}
其中**表示任意目录,*表示任意文件
exclude
指定不需要被编译的文件,一般不需要设置
有一个默认值
"exclude":["node_modules", "bower_components", "jspm_packages"]
extends
指定直接使用哪个文件里面的json
3.2 compilerOptions
编译选项是配置文件中非常重要的配置选项,与include同级
target
编译版本,默认是es3,兼容性较好
"compilerOptions":{
"target": "ES5"
}
module
模块化规范,比如comonjs或者es6,假如不知道有哪些选项,就乱填一个让它报错也行。
"module": "es2015"//也就是es6
lib
指定使用到的库
document也用到了名为dom的库。
一般不用设置它,默认选项就足够了。
outDir
设置编译输入的位置。
"outdir": "./dist"
outFile
将编译后的js合并成一个文件。
"outFile": "./dist/app.js"
会将全局作用域中合并,用的也比较少。
allowjs
是否编译js文件,默认是false。
"allowJs":true
checkJs
是否检查js文件语法,默认也是false。
true之后就会用ts的语法来检查js文件。
removeComments
是否移除注释,默认是false
noEmit
不生成编译后文件。用的少。只能用来检查语法。
noEmitOnError
ts语法错误时不编译成js
下面就是语法的严格检查了。
alwaysStrict
编译后的文件默认不使用严格模式,严格模式的性能要好一点
模块化文件就是在严格模式之下了,所以如果用到了import 和export的时候不会有"use strict"
noImplicitAny
不允许使用隐式的any,默认false
比如let a = 5就是一个隐式的。
noImplicitThis
不允许使用隐式的this,默认false
strictNullChecks
严格检查空值,当你用dom查询一个元素的时候,可能这个元素不存在,但是你将它赋值给一个变量了,这个变量就有可能是空值。
let test1 = document.getElementById("test1");
test1.addEventListener("click", ()=>{});
可以设置
if(test1){
test1.addEventListener("click",()=>{});
}
strict
所有严格检查的总开关
将strict设置为true就可以不设置上面的严格检查了。
建议打开。
4 webpack配置
这一步需要有webpack基础,假如是使用vue和react就不需要自己配置了。
除了安装webpack必须的webpack webpack-cli
安装打包ts的文件typescript和ts-loader
npm i webpack webpack-cli ts-loader typescript -D
module里面的配置
module: {
rules: [
{
test: /.ts$/,
use: "ts-loader",
exclude: /node-modules/
}
]
}
5 类
类的用法和js中es6的类差不多。
class Person{
//实例属性
name:string = "孙悟空";
readonly id:string = 123;
static sayHello():void{
console.log("hello");
}
}
构造函数
class Dog(){
name:string;
age:number;
constructor(name: string, age:number){
this.name = name;
this.age = age;
}
}
const dog = new Dog("131", 12);
接下来的继承 super 抽象类, 接口都和java差不多。
抽象类
抽象类只能用来继承,不能实现,也可以在里面写抽象方法。
abstract class Animal{
name:string;
abstract sayHello:void;
}
class Dog extends Animal{
sayHello(){
console.log("31113");
}
}
接口
接口就是用来定义一个类的结构的。
type mytype = {
name: string,
age: number
};
const obj1:mytype = {
name: "ss",
age: 11,
}
interface mytype2 = {
name: string;
age: number;
}
//可以用来替代type来声明对象
const obj2:mytype2 = {
name: "3131",
age: 11,
}
//需要实现接口中的所有内容
class myClass implements mytype2{
name: string,
age: number
}
private与public
private不能被直接访问,只能在类内部使用,可以用getter和setter设置。
protected比起private还能在子类中使用。
public就没有限制了。
class Person{
private _name:string;
private _age:number;
get name(){
return this._name
}
set name(value){
this._name = value;
}
}
泛型
//类型不确定的时候,用fn<T>来声明函数
functin fn<T>(a:T):T{
return a;
}
fn(10);
fn<string>("hello");
但是这样写的话限制太少了。
可以用接口给泛型加限制。
interface Inter{
length: number;
}
function fn<T extends Inter>(a:T):number{
return a.length;
}
这个时候a必须实现inter接口,也就是T类型的变量必须有length这个属性。
6 导入外部资源的问题
js包
如果你开启严格模式用ts导入js的包,那么会提示你包不存在。
解决方法有两个
1 正式一点的包会有专门为ts服务的包,一般是@types/包名
2 定义一个declaration.d.ts,这样写,比如我想要在ts中导入gsap包,declare module "gsap";
注意在tsconfig.json中将declaration.d.ts也纳入编译中
{
"compilerOptions": {
"module": "ES2015",
"target": "ES2015",
"strict": true
},
"include": ["src", "declaration.d.ts"]
}
导入图片
也需要在declaration.d.ts中将各个类型的图片定义成module
declare module "gsap";
declare module "dat.gui";
declare module '*.svg'
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.gif'
declare module '*.bmp'
declare module '*.tiff'
然后就可以和模块一样导入这张图片,在需要使用图片的地方直接放入这个对象即可。
import imag2 from "../assets/textures/bg.jpg"