TypeScript
环境搭建
- 全局安装 npm i -g typescript
- 执行命令 tsc xxx.ts — 这就可以将ts文件转化为js文件了
基本类型
-
类型声明
-
语法:
let 变量: 类型; let 变量: 类型 = 值; function fn(参数:类型,参数:类型):类型 { // xxx }
-
-
自动类型判断
- TS拥有自动的类型判断机制
- 当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型
- 所以如果你的变量的声明和赋值是同时进行的,可以省略掉类型声明
-
类型
类型 例子 描述 number 1,-33,2,5 任意数字 string ‘asd’,‘qwr’ 任意字符串 boolean true,false 布尔值ture或false 字面量 其本身 限制变量的值就是该字面量的值 any * 任意类型(相当于就是原生js,就是关闭类型检测,其实不写any也可以,默认就是any) unknown * 类型安全的any void 空值(undefined) 没有值(或undefined) never 没有值 不能是任何值 object {name: ‘孙悟空’} 对象 array [1,2,3] 数组 tuple [4,5] 元素,TS新增类型,固定长度的数组 enum enum{A, B} 枚举,TS中新增的类型
let a: number
a = 10
a = 'hellp' // a的类型是number,在以后的使用过程只能是数字,此行代码会报错
// 声明完变量直接赋值
let c: boolean = false
// 但是这种情况下可以省略,会自动判断
let c = false
// 这样就可以限制入参的类型了
// 在ts文件里面参数个数多传少传也会报错
// 第三个number表示返回值期望是一个number
fucntion sum(a: number, b: number): number {
return a + b
}
// 字面量的使用,就是只能是其本省
let a : 10;
a = 10 // 这样a只允许等于10,用的少
let b : 'male' | 'female' // 这样a可以等于两个,一般这样用
// 还有联合类型
let a: boolean | string // 这样a可以为两种类型
// any和unknow的区别,unknow实际就是一个类型安全的any,不能直接赋值给其他变量
let d: any
let e: unknow
let s: string
s = d // 此时s也变成any了,any就祸祸别人了
s = e // 这时候会报错,unknow会安全
e = 'unknow'
// 类型断言 可以告诉解析器变量的实际类型
// 下面两种用法都一样
s = e as string;
s = <string>e
// void,以函数为例
funtion fn(): void {
// xxx
return null
return undefined
// 不反回都可以
}
// never,表示永远不会返回结果
function fn2(): never {
throw new Error('报错了')
// 不反回
}
// object 表示一个对象,如下都可以
let a: object
let a: {}
a = function fn() {}
// 实际我们是为了限制里面的属性,{}这样我们可以指定对象里面可以包含哪些属性
// 语法:{属性名:类型},加上问号表示可选属性
let b: { name:string, age?" number" }
b = { name: '孙悟空' }
// 表示要有a,其他都有多少都行
let c: {name: string, [propName: string] : any} // 这里propName写啥都行,类似形参。这样有name,其他有啥不管
// 设置函数的结构声明
let d: (a:number,b:number)=>number
d = function (n1: number, n2: number): number {
return n1 + n2
}
// string[] 表示字符串数组
let e: string[];
e = ['1', '2', '3']
// number[] 表示数值数组
let f: number[];
let f: Array<number>
f = [1,2,3]
// 元组 一个固定长度的数组
let h : [string, strign]
// enum 枚举值
enum Gender{
Male = 0,
Feal = 1
}
let i : {name: string, gender: Gender}
i = {
name: '孙悟空',
gender: Gender.Male
}
// 连接
let j: {name: string} & {age: number}
j = {name: '孙悟空', age: 18}
// 类型别名
type myType = 1 | 2 | 3 | 4;
let k: myType
编译选项
tscconfig.json文件配置
tsc -w 可以编译文件且实时监控
{
// 这是ts编译器的配置文件,在根目录里
"include": ["src/**/*", "tests/**/*"], // 定义希望被编译文件所在的目录(一个*表示任意文件,两个**表示任意目录)
"exclude": ["./src/hello/**"], // 定义需要排除在外的目录(默认是有node_modules,bower——components,jspm——packages)
"extends": "./configs/base", // 定义需要被继承的配置文件
"files": [], // 指定被编译文件的列表,只有需要编译文件少的时候才会用到
// 编译器的选项
"compilerOptions": {
"target": "es3", // 指定编译后js的版本
"module": "commonjs", // 指定要使用模块化的规范(none,commonjs,amd,systen,umd,es6)
"lib": [], // 指定用到那些库,一般在浏览器运行不用配置
"outDir": "./dist", // 编译后文件所在的目录
"outFile": "./dist/app.js", // 将代码合并为一个文件,所有的全局作用域的代码都合并到一个中
"allowJs": "false", // 是否对js文件进行编译,默认为false
"checkJs": "false", // 是否检查js语法规范,默认为false,用ts规范检查
"removeComments": "false", // 是否移除注释
"noEmit": "false", // 不生成编译后文件,有时候只是检查一下,不编译
"noEmitOnError": "false", // 编译有错误不生成编译文件
"strict": "false", // 所有严格检查的总开关
"alwaysStrict": "false", // 编译后的文件是否使用严格模式(如果文件里面有export,import,就不会有use strict,因为前两者就默认是严格模式了)
"noImplicitny": "false", // 不允许隐式any类型
"noImplicitThis": "false", // 不允许不明确类型的this
"strickNullChecks": "false", // 严格的检查空值
}
}
通过webpack来使用TS打包
- npm i -D webpack web pack-cli typescript ts-loader
- 新建webpack.config.js(做好内部的相关配置)
- 根目录下心间tsconfig.json文件
- 在package.json里面配置命令,“build”: “webpack” 即可
webpack常用插件
- HTMLWebpackPlugin 生成html文件
- Webpack-deb-server 生成一个本地服务器,热启动
- Clean-webpakc-plugin打包前清除打包出口文件
- 需要在resolve配置extensions增加ts文件,使得ts文件可以被引入
引入babel ---- 把新语法转换成旧语法
- @babel/core – babel核心工具
- @babel/preset-env – babel预先设置的环境
- babel-loader – 属于把babel和webpack结合的工具
- core-js – 提供一个更新的js运行环境
Webpack.config.js
// 指定webpack打包时要使用的模块
module: {
// 指定要加载的规则
rule" [
{
// test指定的事规则生效的文件
test: /\.ts$/,
// 要使用的loader,这个use是从后往前执行的
use: [
{
loader: 'babel-loader',
// 设置巴格莱
options: {
// 设置预定义的环境
presets: [
// 指定环境的插件
"@babel/preset-env",
// 配置信息
{
// 兼容的目标浏览器
targets: {
"chorm": "88"
},
// 指定corejs的版本
"corejs": "3",
// 使用corejs的方式,“usage”表示按需加载
"useBuiltIns": "usage"
}
]
}
}
'ts-loader'
],
// 要排除的文件
exclude: /node-modules/
}
]
}
面向对象
类(class)
-
定义类:
-
class 类名 { 属性名:类型; constructor(参数: 类型) { this.属性名 = 参数 } 方法名() { // xxx } }
-
示例:
class Person { // 直接定义的属性是实例属性,需要通过对象的实例去访问 // 使用static开头的属性是静态属性(类户型),可以直接访问 // 定义实例属性 readonly name: string // 加上readonly就只能读不能改了,不加实例可以改可读 age: number static readonly name: number = 18 // 静态只读属性 // 这里面是实例属性 // 构造函数会在对象创建时候调用 constructor(name: string, age: number) { // this表示当前的实例 this.name = name; this.age = age } // 定义实例方法 sayHello() { console.log('say Hello') // 在方法中可以通过this来表示当前调用方法的对象 console.log(this) } // 定义静态方法 static sayHello() { console.log('say Hello') } } const per = new Person()
-
类的继承
/*
* 抽象类(比如上述的Animal,我们希望他不能被直接实例话,因为Animal是用来让别人继承的,就把他归为超类)
* 就在前面加一个abstract,避免他被别人创建对象
* 只有在抽象类中可以添加抽象方法
* 抽象方法,前面加一个abstract,只定义方法的结构
*/
abstract class Animal {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
abstract sayHello():void;
}
/*
* - extends继承,子类将继承父类的所有方法和属性,不会继承静态属性和方法
* - 此时,Animal被称为父类,Dog被称为子类
* - 可以将多个类中共有的代码写在一个父类当中,这样只需要写一次
* - 如果在子类中添加了和父类相同的方法,则会覆盖父类的方法,称为方法的重写
*/
class Dog extends Animal {
}
class Cat extends Animal {
age: number;
constructor(name: string) {
// 如果在子类写了构造函数,其实就是会将父类的构造函数覆盖掉,所以必须对父类的构造函数进行调用
super(name)
this.age = age
}
sayHello() {
console.log('喵喵喵')
// 在类的方法中,super就表示当前类的父类,也可以理解为父类的实例
super.sayHello()
}
}
接口
// 举例 -- 描述对象类型
type myType = {
name: string,
age: number
}
// 接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法
// 同时也可以当成类型声明去使用,跟上面那个普通的类型声明可以
// 接口定义是可以重复声明,但是type不行
interface myInterface{
name: string,
age: number
}
interface myInterface{
genter: string
}
const obj: myInterface = {
name: 'xxx',
age: 18,
genter: 'male'
}
/*
* 接口可以在定义类的时候去限制类的结构
* 接口中所有的属性都不能有实际的值
* 接口只定义对象的结构,而不考虑实际值
* 在接口中所有的方法都是抽象方法
*/
interface myInter{
name: string,
sayHello():void
}
class Myclass implements myInter{
name: string
constructor(name: string) {
this.name = name
}
sayHello() {
console.log('大家好~~')
}
}
属性
class Person {
// TS可以在属性前面添加属性修饰符
public name: string, // 默认值,可以在任意位置访问修改
private age: number, // 私有属性,只能在类的内部进行访问(修改),子类不能访问
protected gender: string, // 保护属性,就是一个折中,在类里面可以访问,子类也可以访问
// 可以在类中添加方法可以使得私有属性可以被外部访问
// 这里跟vue的双向数据绑定原理一致
getAge() {
return this.age
}
setAge(val: number) {
if (val >= 0) {
this.age = val
}
}
constructor(name: string, age: number, public gender: string) { // 这里可以有个快捷写法,直接在传参定义修饰符
this.name = name;
this.age = age
}
// TS中设置getter方法的一个快捷方式 -- 起1
get name() {
return this.name
}
set name(value: string) {
this.name = value
}
}
const per = new Person('张三', 18)
console.log(per.name) // 呼1 -- 这样不会改变我们的使用习惯
泛型
/*
* 在定义函数或者是类的时候,如果遇到类型不明确就可以使用泛型
* 使用:<T> 定义一个叫T的类型,也可以叫其他
然后在后面就是用这个型
其实本质就是设置一个x一样,前后需要保持一致
*/
function fn<T>(a: T): T {
return a
}
// 可以直接使用具有泛型的函数
fn(10); // 不指定,TS可以自己推断
// 对于比较复杂也可以手动指定
fn<string>('hello') // 指定泛型
// 指定多个泛型
function fn2<T, K>(a: T):K{
return a.toString()
}
fn2<number, string>(12)
// 如果还想限定泛型的范围
interface Inter{
length: number,
}
function fn3<T extends Inter>(a: T):number{
return a.length
}
fn3<Inter>({length: 10})
class MyClass<T> {
// xxx
}
视频后面还有一个贪吃蛇的项目,可以用于练习