typescript简单入门

196 阅读7分钟

本笔记基于已经有js基础

未有js基础的请酌情查阅

数据

类型声明

let 变量: 数据类型

let 变量: 数据类型 = 值
// 简写为
let 变量 = 值

function fn (参数1: 数据类型, 参数2: 数据类型 ...): 返回数据类型 {
    ...
    return ...
}

数据类型

数据类型说明例子
number数字1, -33, NaN
string字符串'h12', "h123",
boolean布尔值true、false
字面量限制变星的值就是该字面量的值它本身
any任意类型,默认1,'333'
unknown类型安全的any*
void空(类似于undefined)
never不能是任何值没有值
object任意JS对象{name: 'joe'}
array任意JS数组[1,2,3,4]
tuple元素,TS新增类型,固定长度数组[4,5]
enum枚举,TS新增语法enum{A, B}
  • any 与 unknown区别
let a: any
a = true

let b: unknowm
b = 'false'

let c: string
c = a // 不报错
c = b // 报错

// 不报错的赋值方式之一
if (typeof b === 'string') {
    c = b
}

// 不报错的赋值方式之二:类型断言
c = b as string
c = <string> b
  • object 属性设置
// object: 无限制
let a: object
a = { a: 123 }
a = (): void => {}
a = []
// 但不能是js简单类型
a = 12

// object: 有限制
let b: { name: string }
b = { name: '猴子' }
// 报错
b = { name: '猴子', age: 6000 }
// 报错原因:字面量内部没有其他属性

// object: 选填向
let c: { name: string, age?: number }
c = { name: '大象'age: 30 }
c = { name: '大象' }

// object: 自定义
let d: { [propName: string]?: string }
d = { a: 'a', b: 'b', c: 'c' }
  • 函数设置
let a: (a: number, b: number) => number

a = (num1: number, num2: number) => {
    return num1 + num2
}
  • 数组设置
// 字符串数组
let a: string[]
// 数字数组
let b: number[]

// 自定义数组元素
let c: Array <{ name: string }>
c = [
{ name: '123' },
{ name: '123', age: 12 } // 只能有name属性,报错
]
  • 枚举法
enum Sex {
    male = '男' ,
    female = '女'
}

const aaa = (sex: String): boolean => {
    if (sex === Sex.male) {
        return true
    } else if (sex === Sex.female) {
        return false
    } else {
        return false
    }
}

console.log(aaa('男'))

类型别名

  • type
type aaa = 1 | 2 | 3 | 4 | 5
let a: aaa

a = 1
a = 5
a = 6 // 报错

typescript 配置

转化成js

需要全局依赖

# 安装编译
npm i -g typescript

编译

# 编译js
tsc *.ts
# 监视性编译js
tsc *.ts -w

编译文件配置

编译配置文件:tsconfig.json

例子:

// 文件是json格式,这里为了方便展示,采用js写法
{
    // 定义编译哪些文件
    include: [
        './src/**/*.ts'
    ],
    // 定义哪些文件 不 编译
    exclude: [
        './src/hello/**/*.ts'
    ],
    // 指定编译文件列表
    files: [
        'test1.ts',
        'test2.ts',
        'test3.ts',
        'test4.ts'
    ],
    compilerOptions: {
        // 设置ts代码编译的目标版本
        // 值: 'ES5'(默认)、'ES6/ES2015'、'ES7/ES2016'、'ES2017'、'ES2018'、'ES2019'、'ES2020'、'ESNext'(js最新版本)
        target: 'ES5'
    }
}

include属性

定义编译文件的路径

例:

{
    "include": [
        "./src/**/*.ts"
    ]
}

exclude属性

定义不被编译文件的路径

例:

{
    "exclude": [
        "./src/hello/**/*.ts",
        "node_modules"
    ]
}

files属性(不常用)

定义编译文件目录

例:

{
	"files": [
        "test1.ts",
        "test2.ts",
        "test3.ts",
        "test4.ts"
    ]
}

compilerOptions对象

配置 ts 相关对象

属性名称说明可选值/配置范围/类型例子
target转换目标js的版本类型'ES5'(默认)、'ES6/ES2015'、'ES7/ES2016'、
'ES2017'、'ES2018'、'ES2019'、'ES2020'、
'ESNext'(js最新版本)
"ES6"
sourceMap是否生成js地图Boolean类型:true、falsetrue
module模块化转换"none"、"commonjs"、"amd"、"system",
"umd"、"es6"、"es2015"、"es2020"、"esnext"
"es6"
lib指定项目中要使用的库
若是空数组[]
有些默认的库将不会调用
(部分展示)"es5"、"es6"、"dom"、"es2015""dom"
outDir定义文件编译后存放目录String类型"./dist"
outFile将代码合并为一个文件
建议在module属性为amd、system时使用
String类型"./dist/app.js"
allowJs是否编译js文件
与编译文件路径有关
"**/*.ts"确定文件类型
就无法执行
**/*未定义文件类型
可以执行
Boolean类型:true、false(默认)true
checkJs检测编译js文件语法规范
按照ts常规标准
如改变数据类型就会出错
Boolean类型:true、false(默认)true
removeComments是否移除注释Boolean类型:true(默认)、falsetrue
noEmit是否停止生成编译文件Boolean类型:true、false(默认)false
noEmitOnError出现错误时是否生成编译文件Boolean类型:true(默认)、falsetrue
alwaysStrict是否执行js严格模式Boolean类型:true(默认)、falsetrue
noImplicitAny是否禁止使用隐性any类型
比如说函数参数之类
Boolean类型:true、false(默认)true
noImplicitThis是否禁止使用不明确this
比如说函数内部this
Boolean类型:true、false(默认)false
strictNullChecks是否严格检查空值Boolean类型:true、false(默认)false
strict严格检查总开关Boolean类型:true、false(默认)false
lib全部属性
'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'es2021', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'webworker.iterable', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays','es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2020.bigint', 'es2020.promise', 'es2020.sharedmemory', 'es2020.string', 'es2020.symbol.wellknown', 'es2020.intl', 'es2021.promise', 'es2021.string', 'es2021.weakref', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise', 'esnext.weakref'

typescript 对象类

class test {}
  • 修饰词
修饰词说明
readonly只读状态
static静态类型
private私有状态
public公有状态

属性封装

在不使用private情况下,默认为public,若是属性采用public,外部可以直接手动修改属性,不安全

故要专门写get/set方法来封装属性,并且将属性私有化private

class test {
    private name: string
    private age: number
    
    setName (name: string): void {
        this.name = name
    }
    setAge (age: string): void {
        this.age = age
    }
    getName (): string {
        return name
    }
    getAge (): number {
        return age
    }
}

构造函数

创建一个对象时会调用构造函数

class test {
    private name: string
    private age: number
    constructor (name: string, age: number) {
        this.name = name
        this.age = age
    }
    ......
}

继承与super

类可以继承

class animal {
    ......
}
    
class dog extends animal {
    constructor () {
        super ()
    }
}

super 意思是调用父类,如调用父类构造函数调用方法

class animal {
    ......
}
    
class dog extends animal {
    constructor () {
        // 调用父类的构造函数
        super ()
    }
    
    sayHello () {
        // 调用父类的sayHello方法
        super.sayHello()
    }
}

抽象类

可以参考工厂模式,将类抽象化,被抽象的类只会有相关的属性和方法名,但不能具体化

抽象类 Product

abstract class Product {
    abstract show (): void
}
export default Product

抽象类 Factory

import Product from './Product'

abstract class Factory {
    abstract getProduct (): Product
}
export default Factory

可以通过继承抽象类,并完成抽象类对应的方法

实体类ProductA

import Product from './Product'

class ProductA extends Product{
    show(): void {
        console.log('这是产品A')
    }
}

export default ProductA

实体类FactoryA

import Factory from './Factory'
import ProductA from './ProductA'

class FactoryA extends Factory {
    getProduct(): ProductA {
        return new ProductA()
    }
}

export default FactoryA

调用时

import FactoryA from './FactoryA'

let factoryA = new FactoryA()
factoryA.getProduct().show()
// 这是产品A

接口

特点1:接口可以重复声明,最后调用时会将之前声明的东西合并

特点2:接口内的数据只能声明数据类型,不能赋值,包括函数

特点3:创建接口对象时,必须将内部必填部分补全,不能填写不存在部分

interface myInter {
    name: string
    sayHello (): void
}

interface myInter {
    age: number
}

使用:对象使用

interface personalInfo {
    name: string
    age: number
}

const obj = {
    name: '张三',
    age: 18
}

使用:类使用

interface test1 {
    name: string
    age: number
    setName (name: string): void
    setAge (age: number): void
    getName (): string
    getAge (): number
}


class tttttt implements test1 {
    // 内部定义的name、age不能用private来修饰
    name: string
    age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    setName (name: string): void {
        this.name = name
    }
    setAge (age: number): void {
        this.age = age
    }
    getName (): string {
        return this.name
    }
    getAge (): number {
        return this.age
    }
}

const a = new tttttt('张三', 18)
console.log(a)

泛型

一般用于函数/方法、类

function fn <T> (a: T): T {
    return a
}

泛型一般是用于不清楚 传参 的数据类型,但使用any就会有数据类型转换风险

  • 在执行时规定其数据类型
// <T> 代表创建泛型T, 函数内就可以调用泛型T
function fn <T> (a: T): T {
    return a
}

fn <number> (11)
fn <number> ('11') // 报错!
  • 这规定同样在class类中也通用
class Test <T> {
    private id: string
    private attr1: T
    private attr2: T
    constructor(id: string, attr1: T, attr2: T) {
        this.id = id
        this.attr1 = attr1
        this.attr2 = attr2
    }
}

const aaa = new Test<number>('a111', 12, 22)
const bbb = new Test<number>('a111', 12, '22') // 报错
  • 一次性可以创建多个泛型
const fn = <T,K> (a: T, b: K): T | K => {
    if (parseInt(a.toString()) > parseInt(b.toString())) {
        return a
    } else {
        return b
    }
}

console.log(fn <number, string> (222, '33'))

  • 还可以继承接口类
interface myInter {
    length: number
}

const fn = <T extends myInter> (a: T): number => {
    return a.length
}

console.log(fn({length: 333, other: '555'}))