文章內容輸出來源:拉勾大前端高薪訓練營
TypeScript 概述
TypeScript 是基于 JavaScript 基礎之上的編程語言,是 JavaScript 的超集(superset) 或者叫 擴展集 蜓耻。任何一種 JavaScript 運行環(huán)境都支持
TypeScript 在JavaScript之上多了一些擴展特性:類型系統(tǒng)械巡、ES6+,最終編譯成原始的JavaScript有勾。
TypeScript 解決 JavaScript 自由的類型系統(tǒng)的問題古程,大大提高代碼的可靠程度挣磨。
相比較于 Flow ,TypeScript 功能更為強大,生態(tài)也更健全塘砸、更完善呜达。
目前 Angular/Vue.js 3.0 已經(jīng)使用 TypeScript。
TypeScript 是前端領域中的第二語言
缺點:(相對于JavaScript)
- 語言本身多了很多概念眉踱,但是 TypeScript 屬于[漸進式]:即便什么特性都不知道霜威,可以立馬按照JavaScript 標準語法來編寫代碼,可以了解一些特性婿禽,使用一些特性
- 項目初期,TypeScript 會增加一些成本
基本使用
tsc 命令 作用:編譯TypeScript文件淀零,編譯過程中先去檢查代碼中的類性使用異常膛壹,移除掉一些類型注解之類的擴展語法模聋,自動轉換ES的新特性。
//初始化 package.json 用來管理項目的依賴項
yarn init -yes
//作為項目的開發(fā)依賴安裝持痰,它提供 tsc 命令
yarn add typescript --dev
//編譯文件
yarn tsc index.ts
tsc 命令 不僅可以編譯指定的某個ts文件祟蚀,還可以編譯整個工程。
一般編譯項目之前移剪,先創(chuàng)建一個 typescript 的配置文件
//生成 tsconfig.json 文件
yarn tsc --init
使用薪者,直接運行命令:yarn tsc
TypeScript 基本應用
1言津、原始數(shù)據(jù)類型
標準庫就是內置對象所對應的聲明
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 不單指對象慰安,指除了原始類型以外的其他類型
- 對象的類型限制可以使用類似字面量語法的方式聪铺,更專業(yè)的方式是接口
const foo: object = function () {}
const obj: { foo: number, bar: string } = { foo: 123, bar: 'string' }
5铃剔、數(shù)組類型
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、元組類型:
明確元素的個數(shù)和每個元素的類型
react 中useState 這樣的 Hooks 函數(shù)返回的就是元組類型
ES2017中提供 Object.entries()方法獲取對象中所有的鍵值數(shù)組,得到的每一個鍵值就是元組蝶押,因為它是固定長度的
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西设、函數(shù)類型:
函數(shù)可以采用 函數(shù)申明和函數(shù)表達式兩種方式生成答朋。
函數(shù)申明類型約束:
- 函數(shù)每個參數(shù)后面添加類型注解,返回值的類型添加在 括號 后面禽绪。
- 形參和實參 類型和個數(shù)必須要相同
- 可選參數(shù)洪规,在參數(shù)名稱后面添加 '?'斩例,也可以使用es6的參數(shù)默認值的方式,這兩種都必須放在參數(shù)列表的最后
- 任意個數(shù)的參數(shù)使用 rest關鍵詞(...rest)
function func1( a: number, b?:number, c: number = 10, ...rest: number[] ): string {
return 'func1'
}
func1(100, 200);
func1(100);
函數(shù)表達式類型限制:
- 可以使用相同的方式限制函數(shù)的參數(shù)和返回值的類型
- typescript能根據(jù)函數(shù)表達式推斷出這個變量的類型
- 如果回調函數(shù)的方式础钠,必須約束回調函數(shù)形參的類型叉谜,可以使用類似箭頭函數(shù)的方式去表示參數(shù)可以接收什么的函數(shù)
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會根據(jù)變量的使用情況推斷變量的類型。
如果無法推斷就標注為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)
可以理解成 一種規(guī)范或者契約额衙,用來約束對象的結構怕吴,使用一個接口转绷,就必須遵守接口全部的約束
- interface 開頭硼啤,多個字段用 ,/; 也可以不加
- 可選成員、只讀成員煞肾、動態(tài)成員
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'; //報錯
//動態(tài)成員
interface Cache{
[key: string]: string
}
const cache: Cache = {}
cache.foo = 'values';
cache.bar = 'hahha';
13嗓袱、類 Classes
作用:用來描述一類具體事物的抽象特征
代碼中:用來描述一類具體對象的抽象成員
ES6 中開始有專門的class渠抹,TypeScript 增強了 class 的相關語法
- 需要先明確申明類有的一些屬性
- 屬性必須設置默認值(可以在類中定義通過‘=’添加,也可以在構造函數(shù)中初始化)
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吓妆、類 與 接口
接口:抽取公共的特征
實現(xiàn)接口必須要有對應的所有的成員
interface Eat{
eat(food: string): void
}
interface Run{
run(distance: number): void
}
class Person implements Eat, Run{
eat(food: string): void{
console.log(`優(yōu)雅的進餐:${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創(chuàng)建的對應的實例對象狐胎,必須使用子類繼承這個類型
- 抽象方法需要使用 abstract 修飾,不需要方法體
- 父類中有抽象方法時晕鹊,子類必須實現(xiàn)它
可以使用vscode 的代碼修正功能暴浦,自動生成對應的方法實現(xiàn)
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)
定義接口、函數(shù)或累的時候沒有指定具體的類型屑墨,使用的時候再去指定具體的類型
目的:極大程度的復用代碼
//創(chuàng)建指定長度的數(shù)組
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');