TypeScript(一)類型

1. boolean

使用 boolean 定義布爾值類型:

let done: boolean = true
注意:使用構(gòu)造函數(shù)創(chuàng)建的值不是 boolean 類型,而是 Boolean 對象
let bool: boolean = new Boolean(true)

// Type 'Boolean' is not assignable to type 'boolean'.
// 'boolean' is a primitive, but 'Boolean' is a wrapper object. Prefer using 'boolean' when possible.
直接調(diào)用 Boolean 創(chuàng)建的值是 boolean 類型
let bool: boolean = Boolean(false)
console.log(bool) // false

2. number

類似于 javascript ,typescript 支持十進制、十六進制、二進制、八進制字面量。

// 十進制
let num: number = 123
// 十六進制
let x: number = 0xf00d
console.log(x)
// 二進制
let y: number = 0b1010
console.log(y)
// 八進制
let z: number = 0o744
console.log(z)

編譯結(jié)果:

var num = 123
var x = 0xf00d
console.log(x)
// 二進制
var y = 10
console.log(y)
// 八進制
var z = 484
console.log(z)

3. string

和 javascript 一樣,可以使用雙引號("")、單引號('')、反引號(``)表示字符串

let str: string = 'sina'

// 還可使用模板字符串
let fullname: string = 'mike'
let age: number = 12
let info = `the person info:
  name is ${fullname};
  age is ${age}`
console.log(info)

編譯結(jié)果:

var fullname = 'mike'
var age = 12
var info = 'the person info:\n  name is ' + fullname + ';\n  age is ' + age
console.log(info)

4. Array

TypeScript 中有兩種方式表示數(shù)組,比較靈活:

  1. 在元素類型后面接上 [] ,表示由此類型元素組成的一個數(shù)組
// 元素為數(shù)字類型的數(shù)組
let arr: number[] = [2, 3, 4]

編譯結(jié)果:

var arr = [2, 3, 4]
  • 數(shù)組中不允許出現(xiàn)指定類型之外的其他類型:
let nums: number[] = [1, '1', 2, 3, 5]
// Type 'string' is not assignable to type 'number'
  • 數(shù)組個別方法的參數(shù)也會根據(jù)數(shù)組在定義時約定的類型進行限制:
let nums: number[] = [1, 1, 2, 3, 5]
nums.push('8')

// Argument of type '"8"' is not assignable to parameter of type 'number'.
  1. 第二種方式是使用數(shù)組泛型,Array<元素類型>
// 元素為字符串的數(shù)組
let array: Array<string>
array = ['sina', 'mike']
console.log(array)

編譯結(jié)果:

var array
array = ['sina', 'mike']
console.log(array)
  • 如果數(shù)組元素既可以是 number 又可以是 string 類型,可以通過以下方式:
let arr: (string | number)[] = [1, 4, 'sina']
console.log(arr)
注意:指示類型的圓括號()不可以省略,如果省略則會被編譯器認(rèn)為數(shù)組元素是其中一種類型
let arr: string | number[] = [3, 4, 5]
console.log(arr)
// let arr: string | number[] = [3, 4, 5, 'sina'] // 報錯
  • 還可以使用數(shù)組泛型表示元素為多種類型的數(shù)組
let arr: Array<string | number> = [3, 4, 'sina']
console.log(arr)

5. 元組 Tuple

元組可以理解成數(shù)組的擴展,表示一個已知長度和類型的數(shù)組,各元素的類型不必相同

  • 定義一個第一項和第三項為 string 類型,第二項為數(shù)值長度為 3 的數(shù)組
let tuple: [string, number, string] = ['sina', 3, 'mike']
  • 直接對元組類型的變量進行初始化或者賦值的時候,需要提供所有元組類型中指定的項
tuple = ['hello', 33, 'jack']
  • 訪問已知索引的元素:
let tuple: [string, number, string] = ['sina', 3, 'mike']
tuple[2].substr(2) // 'ke'
tuple[1].toFixed(2) // '3.00'
  • 修改某一項的值:
let tuple: [string, number, string] = ['sina', 3, 'mike']
tuple[1] = 22
  • 超出數(shù)組長度的元素稱為越界元素:
const arr: [string, number] = ['sian', 4]
arr[2] = 2
// Tuple type '[string, number]' of length '2' has no element at index '2'.
  • 通過數(shù)組方法修改或者添加元素時,所添加的元素必須是限制類型之一:
let arr: [string, number] = ['hello', 12]

arr.splice(1, 1, 'sina') // ['hello', 'sina']
arr.push(5) // ['hello', 12, 5]
arr.push(true) // 報錯:Argument of type 'true' is not assignable to parameter of type 'string | number'.

6. 枚舉 Enum

枚舉類型用于取值被限定在一定范圍內(nèi)的場景。比如某個值的狀態(tài)由數(shù)字表示,每個數(shù)字對應(yīng)一種狀態(tài),但是我們得記憶或認(rèn)知是對語義化的東西敏感,記不住那些數(shù)字,于是可以通過枚舉表示。

枚舉使用 enum 關(guān)鍵字定義:

enum Status {
  pending,
  resolve,
  reject
}

枚舉成員的序列號默認(rèn)被賦值為從 0 開始遞增的數(shù)字,同時也會對枚舉值到枚舉名進行反向映射:

console.log(Status.resolve) // 1
console.log(Status[2]) // 'reject'

編譯結(jié)果:

var Status
;(function (Status) {
  Status[(Status['pending'] = 0)] = 'pending'
  Status[(Status['resolve'] = 1)] = 'resolve'
  Status[(Status['reject'] = 2)] = 'reject'
})(Status || (Status = {}))

自定義賦值

  1. 可以給枚舉項手動賦值,未手動賦值的枚舉項會接著上一個枚舉項遞增。
enum Days {
  Sun = 7,
  Mon = 1,
  Tue,
  Wed,
  Thu,
  Fri,
  Sat
}

console.log(Days.Sun) // 7
console.log(Days.Mon) // 1
console.log(Days.Tue) // 2
console.log(Days.Sat) // 6

如果未手動賦值的枚舉項與手動賦值的重復(fù)了,TypeScript 并不會察覺到這一點的:

enum Colors {
  green = 3,
  red = 1,
  blue,
  orange,
  pink,
  white
}

console.log(Days.orange) // 3
console.log(Days.green) // 3
console.log(Days[3]) // 'orange'
console.log(Days[3]) // 'orange'

以上枚舉項遞增到 orange 時重復(fù)了,但是 TypeScript 并沒有報錯,導(dǎo)致 Colors[3] 的值開始是 green ,之后被 orange 重寫了。

編譯結(jié)果:

var Colors
;(function (Colors) {
  Colors[(Colors['green'] = 3)] = 'green'
  Colors[(Colors['red'] = 1)] = 'red'
  Colors[(Colors['blue'] = 2)] = 'blue'
  Colors[(Colors['orange'] = 3)] = 'orange'
  Colors[(Colors['pink'] = 4)] = 'pink'
  Colors[(Colors['white'] = 5)] = 'white'
})(Colors || (Colors = {}))

所以使用的時候一定注意,不要出現(xiàn)覆蓋的情況。

  1. 手動賦值的枚舉項也可以為小數(shù)或負(fù)數(shù),此時后續(xù)未手動賦值的項的遞增步長仍為 1:
enum Colors {
  green = 3,
  red = 1.5,
  blue,
  orange,
  pink,
  white
}

console.log(Days.orange) // 3
console.log(Days.green) // 3.5
console.log(Days[3.5]) // 'orange'
console.log(Days[3.5]) // 'orange'

7. Void

javasctipt 中如果函數(shù)沒有返回值,默認(rèn)返回 undefined。

void 表示沒有任何類型,在 TypeScript 用 void 表示一個沒有返回值的函數(shù)。

function foo(): void {
  console.log('hello void')
}

函數(shù)執(zhí)行后仍然返回 undefined 。

為什么指定 void 類型,返回仍然是 undefined?

因為默認(rèn)情況下 null 和 undefined 是所有類型的子類型(包括 void)。也就是說可以把 null 和 undefined 賦值給 number 等其他類型的變量。(前提是 strictNullChecks 為關(guān)閉狀態(tài))。

事實上聲明一個 void 類型的變量沒有什么用,因為只能將它賦值為 undefined 或 null( strictNullChecks 是關(guān)閉狀態(tài))

let unusable: void = undefined
unusable = null
// 如果strictNullChecks為開啟狀態(tài)下則會報錯: Type 'null' is not assignable to type 'void'.

如果函數(shù)參數(shù)未指定類型,則隱式具有“any”類型。

const baz = (text): void => {
  console.log(text)
}
// Parameter 'text' implicitly has an 'any' type.

8. Null & Undefined

let u: undefined = undefined
let n: null = null

默認(rèn)情況下,null 和 undefined 是所有類型的子集(包括 void),可以把他們賦值給這些類型的變量。

但是如果開啟了 strictNullChecks 標(biāo)記,null 和 undefined 只能賦值給 void 和它們自己。

9. Never

never 類型表示永不存在的值的類型。比如那些總是會拋出異?;蚋揪筒粫蟹祷刂档暮瘮?shù)表達(dá)式或箭頭函數(shù)表達(dá)式的返回值類型。

function error(): never {
  throw new Error('Oops...)
}

let neverVar = (): never => { while (true) { } }

never 類型是任何類型的子類型,也可以賦值給任何類型;然而,沒有類型是 never 的子類型或可以賦值給 never 類型(除了 never 本身之外)。 即使 any 也不可以賦值給 never。

重點: never 與其他類型的聯(lián)合后,是沒有 never 的

type ET = string | number | never

// ET 實際上只有 string 和 number兩種類型

基于 never 的特性,還可以使用 never 實現(xiàn)一些有意思的功能。比如可以把 never 作為接口類型下的屬性類型,用來禁止寫接口下特定的屬性,如下:

const props: {

  id: number,

  name?: never

} = {

  id: 1
}

props.name = null; // ts(2322))
props.name = 'str'; // ts(2322)
props.name = 1; // ts(2322)

此時,無論我們給 props.name 賦什么類型的值,它都會提示類型錯誤,實際效果等同于 name 只讀

10. 聯(lián)合類型

聯(lián)合類型表示取值可以為多種類型中的一種,使用 | 分隔每個類型。

let foo: string | number
foo = 'sina'
foo = 33

11. 類型斷言

有時候我們比編譯器更清楚某一個值的類型,所以需要通過某種方式告訴編譯器不進行特殊的數(shù)據(jù)檢查和解構(gòu),手動的去指定一個值的類型(好比其它語言里的類型轉(zhuǎn)換),這種方式稱之為類型斷言。

類型斷言有兩種方式:

  1. <類型>值
let str: string = 'sina'
let len: number = (<string>str).length
  1. 值 as 類型
let str: stirng = 'sina'
let len: number = (str as string).length
注意:在 tsx 語法中必須使用 as ,否則 tsx 會把方式當(dāng)作標(biāo)簽去解析。

實例:

當(dāng) TypeScript 不確定一個變量到底是哪個類型的時候,只能訪問此變量聯(lián)合類型里共有的屬性或方法,但有時我們確實需要在還不確定類型的時候就訪問其中一個類型的屬性或方法,如下:

function getLength(str: string | number): number {
  if (str.length || str.length === 0) {
    return str.length
  }
  return str.toString().length
}
// Property 'length' does not exist on type 'string | number'. Property 'length' does not exist on type 'number'.

以上代碼本身沒有問題,在邏輯里都做了兼容性判斷,但是 ts 在編譯時會去判斷 str 的聯(lián)合類型是否都存在 length 屬性,編譯結(jié)果是 str 為 number 時不存在 length 屬性,所以會拋出錯誤。

此時就可以使用類型斷言將參數(shù) str 斷言成 string 類型。如下:

function getLength(str: string | number): number {
  if ((<string>str).length || (str as string).length === 0) {
    return (str as string).length
  }
  return str.toString().length
}
注意:類型斷言不是類型轉(zhuǎn)換,斷言成一個聯(lián)合類型中不存在的類型是不允許的:
function getLength(str: string | number): number {
  return (str as boolean).length
}
// Property 'length' does not exist on type 'boolean'. return (str as boolean).length

12. 任意值 Any

any 會跳過類型檢查器對值的檢查,任何值都可以賦值給 any 類型,它通常被稱為 top type。

任意類型的值可以賦值給 any 類型的變量,any 類型的值也可以賦值給任意類型的的變量。

比如:

let num: any

num = 3
num = 'str'

let count: number = 4

count = 3
count = num

任意值類型

  • 一個普通類型的值,在賦值過程中是不允許改變類型的:
let str: string = 'sina'
str = 7

// Type '7' is not assignable to type 'string'.
  • 如果是 any 類型,則允許被賦值為任意類型:
let foo: any = 'sina'
foo = 12
foo = true
console.log(foo)
  • 如果用 const 聲明必須有初始值,和 js 是一致的:
const bar: any = 'sina'
console.log(bar)
  • 聲明一個元素為任意類型的數(shù)組:
const arrAny: any[] = [3, 'sian', true, [3]]
console.log(arrAny)
  • 長度仍然不可越界:
const arrAny1: [string, any] = ['sina', 4]
console.log(arrAny1)

任意值的屬性和方法

  • 任意值上允許訪問任何屬性:
let str: any = 'hello'
console.log(str.foo) // undefined

// 編譯器并不會報錯,轉(zhuǎn)成js后運行報錯:Cannot read property 'bar' of undefined
console.log(str.foo.bar)
  • 也允許調(diào)用任何方法
let str: any = 'sina'
str.getName()

未聲明類型的變量

變量如果在聲明時未指定類型,則會被識別為任意值類型

let str
str = 'sina'
str = 7
str.foo('Tom')

等價于:

let str: any
str = 'sina'
str = 7
str.foo()

13. 未知類型 unknown

表示未知類型的值。any 一樣,所有類型都可以分配給 unknown,實際上是類型安全的 any。

和 any 的區(qū)別:

  1. unknown 是 top type (任何類型都是它的 subtype)。任何類型的值都可以賦值給它,但它只能賦值給 unknown 和 any,因為只有它倆是 top type。

  2. any 既是 top type, 又是 bottom type (它是任何類型的 subtype ),所以任何類型的值可以賦值給 any,同時 any 類型的值也可以賦值給任何類型。 這導(dǎo)致 any 基本上就是放棄了任何類型檢查。

unknown 如果要賦值給其他類型變量,可以先判斷類型在賦值。比如:

使用 typeof

let foo: string
let count: unknown
count = 'hello'
count = true

if (typeof count === 'string') {
  foo = count
}

或者使用類型斷言:

foo = count as string
// 另一種寫法
foo = <string>count

14. 類型推論

如果沒有明確指定類型,那么 TypeScript 會依照類型推論的規(guī)則推斷出一個類型。

let str = 'sina'
str = 3 // Error

等價于:

let str: string = 'sina'

如果定義的時候沒有賦值,不管之后有沒有賦值,都會被推斷成 any 類型而不會被被 ts 進行類型檢查:

let str

str = 'sina'
str = 3

15. 交叉類型

交叉類型是將多個類型合并為一個類型。 把現(xiàn)有的多種類型疊加到一起成為一種類型,它包含了所需的所有類型的特性,使用 & 定義交叉類型。

interface A {
  name: string
  age: number
}
interface B {
  name: string
  gender: string
}

let info: A & B = {
  name: 'jack',
  age: 23,
  gender: 'male'
}

info 既是 A 類型,同時也是 B 類型。

注意:交叉類型取的是多個類型的并集,如果出現(xiàn) key 相同但是類型不同,則該 key 為 never 類型。

16. 類型別名

就是給類型起一個別名

語法:

type 別名 = 類型

type num = string
let count: num = 'str'
type numX = 1 | 2 | 3 | 4
let countX: numX = 3

使用 typeof 關(guān)鍵字把值反推類型

const obj = {
  name: 'jack',
  age: 34
}

type User = typeof obj

那么 User 的類型就是

type User = {
  name: string
  age: number
}

注意:類型別名不能被 extends 和 implements

type 可以通過交叉類型實現(xiàn)繼承。

type A = B & C & D

17. 內(nèi)置對象

ECMAScript 提供的內(nèi)置對象有:String、Number、Boolean、Error、Date、RegExp 等。

const num: Number = new Number(11)
const str: String = new String('hello')
const bool: Boolean = new Boolean(true)
const reg: RegExp = /[0-9]/
const date: Date = new Date()
const err: Error = new Error('oops...')

DOM 和 BOM 內(nèi)置對象有: Document、HTMLElement、HTMLCollection、NodeList、MouseEvent 等。

const html: HTMLElement = document.documentElement
const spans: NodeList = document.querySelectorAll('span')
const lis: HTMLCollection = document.getElementsByTagName('li')

document.addEventListener('click', function (e: MouseEvent) {
  // do...
})

類數(shù)組對象:

function foo() {
  const args: IArguments = arguments
}

更多查看 ts 核心庫聲明文件

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容