TypeScript 概述和基本应用 学习笔记

文章内容输出来源:拉勾大前端高薪训练营

TypeScript 概述

TypeScript 是基于 JavaScript 基础之上的编程语言,是 JavaScript 的超集(superset) 或者叫 扩展集 。任何一种 JavaScript 运行环境都支持
TypeScript 在JavaScript之上多了一些扩展特性:类型系统、ES6+,最终编译成原始的JavaScript。
TypeScript 解决 JavaScript 自由的类型系统的问题,大大提高代码的可靠程度。

相比较于 Flow ,TypeScript 功能更为强大,生态也更健全、更完善。
目前 Angular/Vue.js 3.0 已经使用 TypeScript。
TypeScript 是前端领域中的第二语言

缺点:(相对于JavaScript)

  • 语言本身多了很多概念,但是 TypeScript 属于[渐进式]:即便什么特性都不知道,可以立马按照JavaScript 标准语法来编写代码,可以了解一些特性,使用一些特性
  • 项目初期,TypeScript 会增加一些成本

基本使用

tsc 命令 作用:编译TypeScript文件,编译过程中先去检查代码中的类性使用异常,移除掉一些类型注解之类的扩展语法,自动转换ES的新特性。

//初始化 package.json 用来管理项目的依赖项
yarn init -yes
//作为项目的开发依赖安装,它提供 tsc 命令
yarn add typescript --dev
//编译文件
yarn tsc index.ts

tsc 命令 不仅可以编译指定的某个ts文件,还可以编译整个工程。
一般编译项目之前,先创建一个 typescript 的配置文件

//生成 tsconfig.json 文件
yarn tsc --init 

使用,直接运行命令:yarn tsc

TypeScript 基本应用

1、原始数据类型

标准库就是内置对象所对应的声明
Symbol、Promise 都是 ES2015标准库内置的
console 是DOM 标准库内置的
严格模式下 string、number、boolean 不能为空null
非严格模式下 可以为空

const a: string = 'footbar'
const b: number = 100 //NaN Infinity
const c: boolean = true // false
// const d: string = null
const e: void = undefined 
const f: null = null
const g: undefined = undefined
// const h: symbol = Symbol()

2、中文错误信息

yarn tsc --locale zh-CN

VScode 错误提示可以改配置: typescript locale : zh-CN
不推荐这么做,因为不利于搜索引擎去搜索错误信息

3、作用域

确保跟其它示例没有成员冲突 的办法:

//第一种
(function(){
    const a = 123
})()
//第二种 每个文件添加
export {}

4、Object 类型

  • object 不单指对象,指除了原始类型以外的其他类型
  • 对象的类型限制可以使用类似字面量语法的方式,更专业的方式是接口
const foo: object = function () {}
const obj: { foo: number, bar: string } = { foo: 123, bar: 'string' }

5、数组类型

const arr1: Array<number> = [1, 2, 3]
const arr2: number[] = [1, 2, 3]

function sum(...args: number[]){
  return args.reduce((prev, current) => prev + current, 0)
}
sum(1, 2, 3)

6、元组类型:

明确元素的个数和每个元素的类型
react 中useState 这样的 Hooks 函数返回的就是元组类型
ES2017中提供 Object.entries()方法获取对象中所有的键值数组,得到的每一个键值就是元组,因为它是固定长度的

const tuple: [number, string] = [18, 'zs'];
// const age = tuple[0]
// const name = tuple[1]
const [age, name] = tuple
Object.entries({
  foo: 123,
  bar: 456
})

7、枚举类型:

  • 默认枚举类型的值从0开始累加,也可以设置第一个值,后面的值在这个值基础之上累加,枚举类型的值也可以为字符串,必须每个成员设置值。
  • 枚举类型 会入侵我们到我们运行时的代码(影响我们编译后的结果),编译成双向键值对的对象
  • 如果确定代码中不会使用索引器的方式使用枚举(PostStatus[0]),可以使用常量枚举,enum 前面添加 const,这样在编译过程中枚举会移除掉,用到枚举值的地方替换成对应的枚举值。
// const PostStatus = {
//   Draft: 0,
//   Unpublished: 1,
//   Published: 2
// }
// enum PostStatus {
//   Draft = 0,
//   Unpublished = 1,
//   Published = 2
// }
enum PostStatus {
  Draft,
  Unpublished,
  Published
}
// enum PostStatus {
//   Draft = 6,
//   Unpublished,
//   Published
// }
// enum PostStatus {
//   Draft = 'aaa',
//   Unpublished = 'bbb',
//   Published = 'ccc'
// }
const post = {
  title: 'hello typescript',
  content: 'typescript is a typed superset of javascript',
  status: PostStatus.Draft, //1, 0
}

编译之后

var PostStatus;
(function (PostStatus) {
    PostStatus[PostStatus["Draft"] = 0] = "Draft";
    PostStatus[PostStatus["Unpublished"] = 1] = "Unpublished";
    PostStatus[PostStatus["Published"] = 2] = "Published";
})(PostStatus || (PostStatus = {}));
var post = {
    title: 'hello typescript',
    content: 'typescript is a typed superset of javascript',
    status: PostStatus.Draft,
};

常量枚举

const enum PostStatus {
  Draft,
  Unpublished,
  Published
}
const post = {
  title: 'hello typescript',
  content: 'typescript is a typed superset of javascript',
  status: PostStatus.Draft, //1, 0
}
// 编译后
var post = {
    title: 'hello typescript',
    content: 'typescript is a typed superset of javascript',
    status: 0 /* Draft */,
};

8、函数类型:

函数可以采用 函数申明和函数表达式两种方式生成。
函数申明类型约束:

  • 函数每个参数后面添加类型注解,返回值的类型添加在 括号 后面。
  • 形参和实参 类型和个数必须要相同
  • 可选参数,在参数名称后面添加 '?',也可以使用es6的参数默认值的方式,这两种都必须放在参数列表的最后
  • 任意个数的参数使用 rest关键词(...rest)
function func1( a: number, b?:number, c: number = 10, ...rest: number[] ): string {
  return 'func1'
}
func1(100, 200);
func1(100);

函数表达式类型限制:

  • 可以使用相同的方式限制函数的参数和返回值的类型
  • typescript能根据函数表达式推断出这个变量的类型
  • 如果回调函数的方式,必须约束回调函数形参的类型,可以使用类似箭头函数的方式去表示参数可以接收什么的函数
const func2 = function(a: number, b: number): string {
  return 'func2';
}
const func3: (a: number, b:number) => string = function(a: number, b: number): string {
  return 'func2';
}

9、任意类型:

存在安全问题,不对any做类型检查,任何类型语法上都不会报错。
any 是不安全的,轻易不要使用。

function stringify( value: any ){
  return JSON.stringify(value)
}
stringify('string')
stringify(123)
stringify(true)

10、隐式类型推断:

如果没有明确表明类型,typescript会根据变量的使用情况推断变量的类型。
如果无法推断就标注为any
建议给每个变量添加明确的类型,因为这样会便于后期更直观的理解我们的代码

let age = 18;
age = 'string'; //报错
let foo
foo = 100
foo = 'string'

11、类型断言:

两种方式:as 、<>
断言是编译过程中的概念,转换是运行阶段的概念
类型断言不是类型转换,代码编译过后断言就不存在了

const nums = [110, 120, 119, 112];
const res = nums.find(i => i > 0);
// const square = res * res;
// 第一种 断言方式
const num1 = res as number; 
// 第二种 断言方式
const num2 = <number>res; // 会jsx 标签产生冲突

12、接口(interfaces)

可以理解成 一种规范或者契约,用来约束对象的结构,使用一个接口,就必须遵守接口全部的约束

  • interface 开头,多个字段用 ,/; 也可以不加
  • 可选成员、只读成员、动态成员
interface Post {
  title: string,
  content: string;
  subtitle?: string //可选成员
  readonly summary: string //只读成员
}
function printPost(post: Post){
  console.log(post.title);
  console.log(post.content);
}
const hello: Post = {
  title: 'Hello TypeScript',
  content: 'A javascript superset',
  summary: 'A javascript'
}
printPost(hello);
// hello.summary = 'jajja'; //报错

//动态成员
interface Cache{
  [key: string]: string
}
const cache: Cache = {}
cache.foo = 'values';
cache.bar = 'hahha';

13、类 Classes

作用:用来描述一类具体事物的抽象特征
代码中:用来描述一类具体对象的抽象成员
ES6 中开始有专门的class,TypeScript 增强了 class 的相关语法

  • 需要先明确申明类有的一些属性
  • 属性必须设置默认值(可以在类中定义通过‘=’添加,也可以在构造函数中初始化)
class Person{
  name: string
  age: number
  constructor(name: string, age: number){
    this.name = 'init name';
    this.age = 18
  }
  sayHi( msg: string): void{
    console.log(`I am ${this.name}, ${msg}`)
  }
}

13.1、类的访问修饰符

控制类中成员的可访问级别

  • 默认是 public,
  • private私有属性:不能通过外部访问,只能类的内部使用
  • protected受保护的:不能通过外部访问,只允许在子类中访问
  • readonly只读属性
class Person{
  public name: string
  private age: number
  protected readonly gender: boolean
  constructor(name: string, age: number){
    this.name = 'init name';
    this.age = 18
    this.gender = true
  }
  sayHi( msg: string): void{
    console.log(`I am ${this.name}, ${msg}`)
    console.log(this.age)
  }
}
const tom = new Person('tom', 18);
console.log(tom.name)
// console.log(tom.age)// 报错
// console.log(tom.gender)// 报错
class Student extends Person{
  private constructor(name: string, age: number){
    super(name, age)
    console.log(this.gender)
  }
  static create(name: string, age: number) {
    return new Student(name, age);
  }
}
// const jack = new Student('jack', 18); //报错
const jack = Student.create('jack', 18);

13.2、类 与 接口

接口:抽取公共的特征
实现接口必须要有对应的所有的成员

interface Eat{
  eat(food: string): void
}
interface Run{
  run(distance: number): void
}
class Person implements Eat, Run{
  eat(food: string): void{
    console.log(`优雅的进餐:${food}`)
  }
  run(distance: number){
    console.log(`直立行走:${distance}`)
  }
}
class Animal implements Eat, Run{
  eat(food: string): void{
    console.log(`呼噜呼噜的吃:${food}`)
  }
  run(distance: number){
    console.log(`爬行:${distance}`)
  }
}

13.3、抽象类

class 前面加 abstract, 只能被继承,不能使用new创建的对应的实例对象,必须使用子类继承这个类型

  • 抽象方法需要使用 abstract 修饰,不需要方法体
  • 父类中有抽象方法时,子类必须实现它
    可以使用vscode 的代码修正功能,自动生成对应的方法实现
abstract class Animal{
  eat(food: string): void{
    console.log(`呼噜呼噜的吃:${food}`)
  }
  abstract run(distance: number): void
}
class Dog extends Animal{
  run(distance: number): void {
    console.log(`四脚爬行:${distance}`)
  }
}
const d = new Dog();
d.eat('骨头');
d.run(100);

13.4、泛型(Generics)

定义接口、函数或累的时候没有指定具体的类型,使用的时候再去指定具体的类型
目的:极大程度的复用代码

//创建指定长度的数组
function createNumberArray(length: number, value: number): number[]{
  const arr = Array<number>(length).fill(value);
  return arr;
}
const res0 = createNumberArray(3, 100);
//
function createArray<T>(length: number, value: T): T[]{
  const arr = Array<T>(length).fill(value);
  return arr;
}
const res1 = createArray<number>(3, 100); //[100, 100, 100]
const res2 = createArray<string>(3, 'foo'); // ['foo', 'foo', 'foo']

13.5、类型申明(Type Declaration)

定义的时候没有明确的申明,使用时 申明(declare)
为了兼容普通的js模块
在TypeScript中引入第三方模块,如果模块中不包含对应的类型申明文件,我们就要安装对应的类型申明模块,"@types/模块名", 如果没有 只能自己用 declare 语句申明所对应的模块类型

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