以下文章來(lái)源于公眾號(hào):Vue中文社區(qū) ,作者刀哥
初次見(jiàn)面
官方對(duì)其只用了一句話來(lái)描述
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. Any browser. Any host. Any OS. Open source.
大致意思為,TypeScript 是開(kāi)源的,TypeScript 是 JavaScript 的類(lèi)型的超集,它可以編譯成純 JavaScript。編譯出來(lái)的 JavaScript 可以運(yùn)行在任何瀏覽器上。TypeScript 編譯工具可以運(yùn)行在任何服務(wù)器和任何系統(tǒng)上
- 問(wèn)題: 什么是超集
超集是集合論的術(shù)語(yǔ) 說(shuō)到超集,不得不說(shuō)另一個(gè),子集,怎么理解這兩個(gè)概念呢,舉個(gè)例子
如果一個(gè)集合A里面的的所有元素集合B里面都存在,那么我們可以理解集合A是集合B的子集,反之集合B為集合A的超集
現(xiàn)在我們就能理解為 TypeScript 里包含了 Javascript 的所有特性,這也意味著我們可以將.js
后綴直接命名為.ts
文件跑到 TypeScript 的編繹系統(tǒng)中
Typescript 解決了什么問(wèn)題
一個(gè)事物的誕生一定會(huì)有其存在的價(jià)值
那么 TypeScript 的價(jià)值是什么呢?
回答這個(gè)問(wèn)題之前,我們有必要先來(lái)了解一下 TypeScript 的工作理念
本質(zhì)上是在 Javascript 上增加一套靜態(tài)類(lèi)型系統(tǒng)(編譯時(shí)進(jìn)行類(lèi)型分析),強(qiáng)調(diào)靜態(tài)類(lèi)型系統(tǒng)是為了和運(yùn)行時(shí)的類(lèi)型檢查機(jī)制做區(qū)分,TypeScript 的代碼最終會(huì)被編譯為 Javascript
我們?cè)倩氐絾?wèn)題本身,縮小一下范圍,TypeScript 創(chuàng)造的價(jià)值大部分是在開(kāi)發(fā)時(shí)體現(xiàn)的(編譯時(shí)),而非運(yùn)行時(shí),如
- 強(qiáng)大的編輯器智能提示 (研發(fā)效率,開(kāi)發(fā)體驗(yàn))
- 代碼可讀性增強(qiáng) (團(tuán)隊(duì)協(xié)作,開(kāi)發(fā)體驗(yàn))
- 編譯時(shí)類(lèi)型檢查 (業(yè)務(wù)穩(wěn)健,前端項(xiàng)目中Top10 的錯(cuò)誤類(lèi)型低級(jí)的類(lèi)型錯(cuò)誤占比達(dá)到70%)
正文
本篇文章作為 Vue3
源碼系列前置篇章之一,Typescript
的科普文,主要目的為了大家在面對(duì) Vue3
源碼時(shí)不會(huì)顯得那么不知所措,下來(lái)將介紹一些 Typescript
的基本使用
變量申明
基本類(lèi)型
let isDone: boolean = false
let num: number = 1
let str: string = 'vue3js.cn'
let arr: number[] = [1, 2, 3]
let arr2: Array<number> = [1, 2, 3] // 泛型數(shù)組
let obj: Object = {}
let u: undefined = undefined;
let n: null = null;
類(lèi)型補(bǔ)充
- 枚舉
Enum
使用枚舉類(lèi)型可以為一組數(shù)值賦予友好的名字
enum LogLevel {
info = 'info',
warn = 'warn',
error = 'error',
}
- 元組
Tuple
允許數(shù)組各元素的類(lèi)型不必相同。比如,你可以定義一對(duì)值分別為 string和number類(lèi)型的元組
// Declare a tuple type
let x: [string, number];
// Initialize it
x = ['hello', 10]; // OK
// Initialize it incorrectly
x = [10, 'hello']; // Error
- 任意值
Any
表示任意類(lèi)型,通常用于不確定內(nèi)容的類(lèi)型,比如來(lái)自用戶(hù)輸入或第三方代碼庫(kù)
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
- 空值
Void
與 any 相反,通常用于函數(shù),表示沒(méi)有返回值
function warnUser(): void {
console.log("This is my warning message");
}
- 接口
interface
類(lèi)型契約,跟我們平常調(diào)服務(wù)端接口要先定義字段一個(gè)理
如下例子 point 跟 Point 類(lèi)型必須一致,多一個(gè)少一個(gè)也是不被允許的
interface Point {
x: number
y: number
z?: number
readonly l: number
}
const point: Point = { x: 10, y: 20, z: 30, l: 40 }
const point2: Point = { x: '10', y: 20, z: 30, l: 40 } // Error
const point3: Point = { x: 10, y: 20, z: 30 } // Error
const point4: Point = { x: 10, y: 20, z: 30, l: 40, m: 50 } // Error
可選與只讀 ? 表示可選參, readonly 表示只讀
const point5: Point = { x: 10, y: 20, l: 40 } // 正常
point5.l = 50 // error
函數(shù)參數(shù)類(lèi)型與返回值類(lèi)型
function sum(a: number, b: number): number {
return a + b
}
配合 interface
使用
interface Point {
x: number
y: number
}
function sum({ x, y}: Point): number {
return x + y
}
sum({x:1, y:2}) // 3
泛型
泛型的意義在于函數(shù)的重用性,設(shè)計(jì)原則希望組件不僅能夠支持當(dāng)前的數(shù)據(jù)類(lèi)型,同時(shí)也能支持未來(lái)的數(shù)據(jù)類(lèi)型
- 比如
根據(jù)業(yè)務(wù)最初的設(shè)計(jì)函數(shù) identity
入?yún)?code>String
function identity(arg: String){
return arg
}
console.log(identity('100'))
業(yè)務(wù)迭代過(guò)程參數(shù)需要支持 Number
function identity(arg: String){
return arg
}
console.log(identity(100)) // Argument of type '100' is not assignable to parameter of type 'String'.
為什么不用any
呢?
使用 any
會(huì)丟失掉一些信息,我們無(wú)法確定返回值是什么類(lèi)型
泛型可以保證入?yún)⒏祷刂凳窍嗤?lèi)型的,它是一種特殊的變量,只用于表示類(lèi)型而不是值
語(yǔ)法 <T>(arg:T):T
其中T
為自定義變量
const hello : string = "Hello vue!"
function say<T>(arg: T): T {
return arg;
}
console.log(say(hello)) // Hello vue!
泛型約束
我們使用同樣的例子,加了一個(gè)console
,但是很不幸運(yùn),報(bào)錯(cuò)了,因?yàn)榉盒蜔o(wú)法保證每種類(lèi)型都有.length
屬性
const hello : string = "Hello vue!"
function say<T>(arg: T): T {
console.log(arg.length) // Property 'length' does not exist on type 'T'.
return arg;
}
console.log(say(hello)) // Hello vue!
從這里我們也又看出來(lái)一個(gè)跟any
不同的地方,如果我們想要在約束層面上就結(jié)束戰(zhàn)斗,我們需要定義一個(gè)接口來(lái)描述約束條件
interface Lengthwise {
length: number;
}
function say<T extends Lengthwise>(arg: T): T {
console.log(arg.length)
return arg;
}
console.log(say(1)) // Argument of type '1' is not assignable to parameter of type 'Lengthwise'.
console.log(say({value: 'hello vue!', length: 10})) // { value: 'hello vue!', length: 10 }
交叉類(lèi)型
交叉類(lèi)型(Intersection Types),將多個(gè)類(lèi)型合并為一個(gè)類(lèi)型
interface foo {
x: number
}
interface bar {
b: number
}
type intersection = foo & bar
const result: intersection = {
x: 10,
b: 20
}
const result1: intersection = {
x: 10
} // error
聯(lián)合類(lèi)型
交叉類(lèi)型(Union Types),表示一個(gè)值可以是幾種類(lèi)型之一。我們用豎線 | 分隔每個(gè)類(lèi)型,所以 number | string | boolean表示一個(gè)值可以是 number, string,或 boolean
type arg = string | number | boolean
const foo = (arg: arg):any =>{
console.log(arg)
}
foo(1)
foo('2')
foo(true)
函數(shù)重載
函數(shù)重載(Function Overloading), 允許創(chuàng)建數(shù)項(xiàng)名稱(chēng)相同但輸入輸出類(lèi)型或個(gè)數(shù)不同的子程序,可以簡(jiǎn)單理解為一個(gè)函數(shù)可以執(zhí)行多項(xiàng)任務(wù)的能力
例我們有一個(gè)add
函數(shù),它可以接收string
類(lèi)型的參數(shù)進(jìn)行拼接,也可以接收number
類(lèi)型的參數(shù)進(jìn)行相加
function add (arg1: string, arg2: string): string
function add (arg1: number, arg2: number): number
// 實(shí)現(xiàn)
function add <T,U>(arg1: T, arg2: U) {
// 在實(shí)現(xiàn)上我們要注意嚴(yán)格判斷兩個(gè)參數(shù)的類(lèi)型是否相等,而不能簡(jiǎn)單的寫(xiě)一個(gè) arg1 + arg2
if (typeof arg1 === 'string' && typeof arg2 === 'string') {
return arg1 + arg2
} else if (typeof arg1 === 'number' && typeof arg2 === 'number') {
return arg1 + arg2
}
}
add(1, 2) // 3
add('1','2') //'12'
總結(jié)
通過(guò)本篇文章,相信大家對(duì)Typescript
不會(huì)再感到陌生了
下面我們來(lái)看看在Vue
源碼Typescript
是如何書(shū)寫(xiě)的,這里我們以defineComponent
函數(shù)為例,大家可以通過(guò)這個(gè)實(shí)例,再結(jié)合文章的內(nèi)容,去理解,加深Typescript
的認(rèn)識(shí)
// overload 1: direct setup function
export function defineComponent<Props, RawBindings = object>(
setup: (
props: Readonly<Props>,
ctx: SetupContext
) => RawBindings | RenderFunction
): {
new (): ComponentPublicInstance<
Props,
RawBindings,
{},
{},
{},
// public props
VNodeProps & Props
>
} & FunctionalComponent<Props>
// defineComponent一共有四個(gè)重載,這里省略三個(gè)
// implementation, close to no-op
export function defineComponent(options: unknown) {
return isFunction(options) ? { setup: options } : options
}
以上就是W3Cschool編程獅
關(guān)于重新認(rèn)識(shí)Typescript | Vue3源碼系列的相關(guān)介紹了,希望對(duì)大家有所幫助。