TypeScript笔记

安装

npm i -D typescript

ts不能直接在浏览器环境执行,需要先编译成js文件。
文件编译指令:
tsc [tsfile]
tsc [tsfile] -w 可以自动监视改变并重新编译

类型

number
string
boolean
字面量:声明变量可能的值,不能是别的值或者超出字面量的范围。let a: 10|11;a = 10;
any:任意值,可以被赋值不同类型的值。变量也可以赋值给其它类型的变量,不安全。
unknown:安全的any。可以是任何类型值。变量不允许直接被赋值给其它非unknown类型的变量。
void:空值null或者undefined。
never:不能是任何值。这种返回值一般用于系统报错throw newError()
object:任意js对象。
array:数组。
tuple:固定长度数组。[1,2]声明后就不能变长
enum:枚举。enum{'a', 'b'}

变量声明

let a: number;
a = 1;
let b: string = 'abc'

如果变量声明同时直接赋值,则类型会默认对应声明,
let a = false
a = 123 // 提示错误

sum(a:number, b:number): number { // 声明参数类型和函数返回值类型
return a + b
}
sum(1, '2') // 提示错误,但是编译还是会过,可以通过配置让编译也不通过
sum(1, 2, 3) // 提示错误,参数个数不匹配

使用字面量声明:类似于常量,声明了一个或者多个后,后面的代码赋值不能超出范围。
let a: 'hello'; // a的值只能是'hello'不能声明成别的
a = 'world' // 提示错误
let b: 'hello' | 'world'; // b的值只能是'hello'或者'world'

其他类型:
let a: any; // 不限制任何类型赋值
let b; // 如果声明变量不指定类型也不直接赋值,则类型同any

开发中一般不允许使用any类型,因为any类型的变量可以赋值给任何类型变量,会出现严重的问题:
let a;
a = 10;
a = true;
let b: number;
b = a; // tsc编译不报错

如果真有这种业务场景,推荐使用unknown。unknown相当于是一种安全的any,也可以赋值任意类型,但是不能随便赋值给其它类型的变量,直接复制会报错,如果实现进行过类型检查则可以赋值。
let a: unknown
a = 'hello'
let b: string
if (typeof a === 'string') { // 方式1
b = a
}
b = a as string // 方式2 使用断言,断言就是告诉编译器,这个变量的类型一定为指定类型
b = <string>a // 方式3 另一种断言

let a: object // js中一切皆对象,所以通常不会这样使用,实际上开发者关注的应该是对象的结构(属性方法什么的)
a = {}
a = function(){}
let b: {name: string, age?: number} // 这种使用方式比较推荐,使用b的时候必须设置name属性,age可选
b = {name: 'sony'}
let b: {name: string, [propName: string]: any} // 这种方式也比较推荐,[propName: string]: any表示可以追加任意自定义属性,propName是自定义的名字随便写,string表示属性名类型为字符串
b = {name: 'sony', a: 12}

let a: Function // 声明函数,但是实际上没人这么写,没什么意义,开发者关注的是函数的结构(参数返回值什么的)
let a: (arg1: number, arg2: number) => number // 函数的声明方式

let arr: Array<number> // 声明一个数组,内部元素类型为number
let arr: number[] // 作用和上面的等价

let arr: [number, number] // 声明定长数组,赋值的时候必须一一对应,这种方式的优势在于性能比较好,分配固定的内存空间就ok了

关于枚举enum,它的使用意图和“|”很类似,enum的优势在于兼顾了语义化和存储空间。
例如声明一个变量let a: '男'|'女',业务编码使用的时候没什么问题,但是数据库或者数据传递的时候通常倾向于更小的空间占用,比如存0或者1这种值,enum就可以满足这个需求。
开发中可以先定义一个enum类型的类,使用enum中的元素名就代表对应的值(编译器会默认赋值成0、1这种值)
enum Gender {
Male,
Female
}

let person: {name: string, gender: Gender}

person = {name: '张三', gender: Gender.Male} // 相当于gender: 0

另外,比较特殊的运算符“&”,声明类型的时候表示同时满足的意思:
let o: {name: string} & {age: number} // 表示变量o赋值的时候必须是一个对象并且同时有name和age属性。

额外提一下ts中的“?”和“!”的用法:

  1. 作为运算符:“?”用在三目运算符中(例如a?b:c),“!”表示取反(例如!a)
  2. 参数:“?”用在参数中表示可选项。例如function(a: string, b?: number)
  3. 成员变量:“?”表示可选项,“!”表示此项一定有值且不为null
  4. 安全链式调用:
    ?表示可能为null,如果为null就不往下执行,场景:a.b?.c();
    !表示一定不为null,强制让编译器通过安全检查,场景:a.b!.c();或者a.b!.c = xxx

面向对象

ts的面向对象使用起来与es6基本一致:

// class声明和使用
class Animal {
    static readonly type = '爬行动物' // 静态属性,readonly关键字表示只读
    name = 'lucky' // 实例属性

    // 构造函数
    constructor(name: string = 'lucky') {
        this.name = name
    }

    // 实例方法,同样,加了static就变成类静态方法了
    eat() {
        console.log(this.name + ' is eating...')
    }

    static move() {
        console.log('animal can move')
    }
}
const cat = new Animal('happy')
console.log(cat, Animal.type) // {name: 'happy'} '爬行动物'
console.log('eat: ')
cat.eat()
console.log('move: ')
Animal.move()

class Dog extends Animal {
    eat() {
        console.log('dog: ' + this.name + ' is eating...')
    }
}
console.log(Dog.type)
const dog = new Dog()
console.log(dog, Dog.type)
dog.eat()

interface Human {
    name: string
    eat(): void
    speak(): void
}

class Soldier implements Human {
    name: string = '001'
    private _level: number
    constructor(name: string, level: number) {
        this.name = name
        this._level = level
    }

    get level(): number {
        return this._level
    }
    set level(value: number) {
        this._level = value
    }

    eat(): void {
        console.log(`soldier[level ${this.level}] ${this.name} is eating...`)
    }
    speak(): void {
        console.log(`soldier[level ${this.level}] ${this.name} is speaking...`)
    }
}

const orcSoldier = new Soldier('crom', 1)
orcSoldier.eat()
orcSoldier.speak()

// 泛型,生产中不允许使用any类型,如果确实有场景要应对未知类型,或者类型是使用者自定义的,可以考虑使用泛型
function f<T, K>(t: T, k: K): T {
    console.log(`t: ${t}, k: ${k}`)
    return t
}
console.log(f(5, 3)) // 编译器自动识别类型
console.log(f<string, number>('hello', 1)) // 手动指定类型,更加严谨,推荐方式

es6目前无法支持抽象类、接口、私有属性修饰符private等面向对象的特性,ts编译器支持,但也只局限在检查层面,比如对私有属性赋值,虽然tsc检查错误但是默认仍然可以正常编译成js执行,所以需要配置中"noEmitOnError": true 避免最终代码出现逻辑漏洞。

编译器配置

ts文件的需要先经过编译器执行tsc指令编译成js文件才能在浏览器环境执行,开发过程中我们可以创建一个tconfig.json并根据需求配置参数,编译器会读取配置文件并覆盖默认配置。

ts配置文件跟普通json文件不太一样,里面可以写注释。

{
  /* include:用于编译指定目录下的ts文件,**表示任意目录,*表示所有文件 */
  "include": ["./src/**/*"],

  /* exclude:不编译某些目录下的文件 */

  /* extends:表示继承某些配置文件,用于根据需要拆分组合配置 */

  /* files:直接编译指定文件名,用于小微型的应用开发,不常用 */

  /* compailerOptions: 编译配置项,可以定制编译规则,可以让代码更严谨,减少程序出错概率 */
  "compilerOptions": {
    // target表示编译成什么样的文件,具体指某个es版本,默认会编译成es3,
    // 通常会编译成es6(es2015)再配合webpack的babel-loader处理
    "target": "ES2015",
    // 指定模块化规范
    "module": "ES2015",

    // 指定用到了哪些库,方便ts编译器识别,比如用了dom就可以在代码中使用document否则会编译报错。
    // 这项通常不需要配置,默认配置已经比较全。某些场景如nodejs环境或者用到一些默认不支持的lib会考虑配置
    // "lib": ["DOM"]

    // allowJS和checkJs一般成对使用,默认值是false,表示是否检查和编译js文件,
    // 有些情况下可能出现js文件模块和ts文件模块编译后无法正常使用的问题,这时候会需要把js文件也编译处理一遍
    "allowJs": true, 
    "checkJs": true,

    "removeComments": true, // 是否移除注释,默认是false

    // "noEmit": false // 默认false,不生成编译结果(target),不常用,某些情况下可能只是想使用编译检查功能的时候会设置这项

    // 默认false,只要编译出错就不生成target,
    // 在我们allowJs为true的时候,js文件即使检查有错误,也会执行编译,这可能会出现错误隐患,
    // 如果要严格控制js文件和ts一视同仁,可以设置为true
    "noEmitOnError": true,

    // 严格模式的代码在浏览器环境下执行效率更好,
    // 通常模块化引入的代码默认都是严格模式,有些非模块化代码如果也需要严格模式(开头加use strict),就需要配置此项
    "alwaysStrict": true,

    // 以下是一些常用代码安全检查规则

    // 默认false,如果配置了strict为true,则所有规则选项(包括下面的选项)都会被覆盖为严格模式,如果想订制,则不要配置此项
    // 开发中建议直接配置strict为true
    // "strict": true,

    // 不允许隐式any类型(不明确声明类型),默认是false,any会导致编译器不去判断类型,造成代码隐患 
    "noImplicitAny": true,

    // 不允许隐式this(不明确声明this是什么类型),默认是false,原生js中this的指向非常灵活,跟动态调用环境有关系(执行上下文),
    // 这也是bug隐患,如果是单纯声明一个function内部想用this,可以考虑把“this”作为参数传进来
    "noImplicitThis": true,

    // 是否严格检查null值,默认false,有些操作如获取dom,然后执行dom.xxx()的时候,dom可能获取失败即是null,这样执行就会报错,
    // 为了避免这个隐患,编译器可以配置这个选项为true,代码中可以用if判断包裹,也可以使用ts语法dom?.xxx()
    "strictNullChecks": true

  }
}

ts-loader

开发中我们一般会使用webpack打包代码,使用ts-loader编译ts文件再通过babel-loader解决js的兼容性问题
ts-loader使用的时候建议先到官网上看下版本兼容相关信息,8.x和9.x分别对应webpack4 和webpack5

npm i -D ts-loader typescript

  resolve: {
    // Add `.ts` and `.tsx` as a resolvable extension.
    extensions: [".ts", ".tsx", ".js"]
  },
  module: {
    rules: [
      // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`
      { 
        test: /\.tsx?$/,
        loader: "ts-loader",
        exclude: /node_modules/
      }
    ]
  }

然后别忘了把tconfig.json放到项目根目录下

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容