TypeScript 高級類型總結(含代碼案例)

TypeScript 是一種類型化的語言,容許你指定變量、函數參數、返回的值和對象屬性的類型。前端

如下是 TypeScript 高級類型的使用方法總結,並且帶有例子。程序員

Intersection 類型

Intersection 類型是一種把對多種類型進行組合的方法。這意味着你能夠把給定的多種類型合併,並獲得一個帶有所有屬性的新類型。面試

type LeftType = {
  id: number
  left: string
}

type RightType = {
  id: number
  right: string
}

type IntersectionType = LeftType & RightType

function showType(args: IntersectionType) {
  console.log(args)
}

showType({ id: 1, left: "test", right: "test" })
// Output: {id: 1, left: "test", right: "test"}

代碼中的 IntersectionType 」組合了兩種類型: LeftTypeRightType,並使用 & 符號來構造交 intersection 類型。typescript

Union 類型

Union 類型用來在給定變量中使用不一樣類型的註釋。segmentfault

type UnionType = string | number

function showType(arg: UnionType) {
  console.log(arg)
}

showType("test")
// Output: test

showType(7)
// Output: 7

showType 函數是一個 union 類型,它可以接受字符串和數字做爲參數。服務器

範型類型

泛型類型是一種用來重用給定類型的一部分的方式。它用來處理參數傳入的類型 T微信

function showType<T>(args: T) {
  console.log(args)
}

showType("test")
// Output: "test"

showType(1)
// Output: 1

要構造一個泛型類型,須要用到尖括號並將 T 做爲參數進行傳遞。多線程

在下面的代碼中,我用的是 T(這個名稱隨你決定)這個名字,而後使用不一樣的類型註釋調用了兩次 showType 函數,由於它是能夠重用的。框架

interface GenericType<T> {
  id: number
  name: T
}

function showType(args: GenericType<string>) {
  console.log(args)
}

showType({ id: 1, name: "test" })
// Output: {id: 1, name: "test"}

function showTypeTwo(args: GenericType<number>) {
  console.log(args)
}

showTypeTwo({ id: 1, name: 4 })
// Output: {id: 1, name: 4}

還有另外一個例子,例子中有一個接口 GenericType,這個接口接收通用類型 T。因爲它是可重用的,所以咱們能夠用字符串和數字來調用它。ide

interface GenericType<T, U> {
  id: T
  name: U
}

function showType(args: GenericType<number, string>) {
  console.log(args)
}

showType({ id: 1, name: "test" })
// Output: {id: 1, name: "test"}

function showTypeTwo(args: GenericType<string, string[]>) {
  console.log(args)
}

showTypeTwo({ id: "001", name: ["This", "is", "a", "Test"] })
// Output: {id: "001", name: Array["This", "is", "a", "Test"]}

泛型類型能夠接收多個參數。在例子中傳入兩個參數:TU,而後將它們用做屬性的類型註釋。也就是說,咱們如今能夠給這個該接口並提供兩個不一樣的類型做爲參數。

實用工具類型

TypeScript 提供了方便的內置實用工具,可幫助咱們輕鬆地操做類型。在使用時須要將要處理的類型傳遞給 <>

Partial

  • Partial<T>

Partial 容許你將全部類型爲 T 的屬性設爲可選。它將在每一個字段旁邊添加一個 ? 標記。

interface PartialType {
  id: number
  firstName: string
  lastName: string
}

function showType(args: Partial<PartialType>) {
  console.log(args)
}

showType({ id: 1 })
// Output: {id: 1}

showType({ firstName: "John", lastName: "Doe" })
// Output: {firstName: "John", lastName: "Doe"}

代碼中有一個名爲 PartialType 的接口,它做爲函數 showType() 的參數的類型註釋。要想使屬性是可選的,必須用到 Partial 關鍵字,並傳入 PartialType 類型做爲參數。如今全部字段都變成了可選的。

Required

  • Required<T>

Partial 不一樣,Required 使全部類型爲 T 的屬性成爲必需的。

interface RequiredType {
  id: number
  firstName?: string
  lastName?: string
}

function showType(args: Required<RequiredType>) {
  console.log(args)
}

showType({ id: 1, firstName: "John", lastName: "Doe" })
// Output: { id: 1, firstName: "John", lastName: "Doe" }

showType({ id: 1 })
// Error: Type '{ id: number: }' is missing the following properties from type 'Required<RequiredType>': firstName, lastName

即便在以前先將它們設爲可選的,Required 也會使全部符合條件的屬性成爲必需的。並且若是省略掉屬性的話TypeScript 將會引起錯誤。

Readonly

  • Readonly<T>

這個類型會對全部類型爲 T 的屬性進行轉換,使它們沒法被從新賦值。

interface ReadonlyType {
  id: number
  name: string
}

function showType(args: Readonly<ReadonlyType>) {
  args.id = 4
  console.log(args)
}

showType({ id: 1, name: "Doe" })
// Error: 沒法給'id'從新賦值,由於它是隻讀屬性。

在代碼中用 Readonly 來使 ReadonlyType 的屬性不可被從新賦值。若是你必定要爲這些字段賦值的話,將會引起錯誤。

Besides that, you can also use the keyword readonly in front of a property to make it not reassignable.
除此以外,還能夠在屬性前面使用關鍵字「 readonly」,以使其沒法從新分配。

interface ReadonlyType {
  readonly id: number
  name: string
}

Pick

  • Pick<T, K>

它容許你經過選擇某個類型的屬性 k ,從現有的模型 T 中建立一個新類型。

interface PickType {
  id: number
  firstName: string
  lastName: string
}

function showType(args: Pick<PickType, "firstName" | "lastName">) {
  console.log(args)
}

showType({ firstName: "John", lastName: "Doe" })
// Output: {firstName: "John"}

showType({ id: 3 })
// Error: Object literal may only specify known properties, and 'id' does not exist in type 'Pick<PickType, "firstName" | "lastName">'

Pick 與前面看到的那些有點不一樣。它須要兩個參數 —— T 是要從中選擇元素的類型,k 是要選擇的屬性。還能夠通用管道符號 (|)將它們分開來選擇多個字段。

Omit

  • Omit<T, K>

OmitPick 相反。它從類型 T 中刪除 K 屬性。

interface PickType {
  id: number
  firstName: string
  lastName: string
}

function showType(args: Omit<PickType, "firstName" | "lastName">) {
  console.log(args)
}

showType({ id: 7 })
// Output: {id: 7}

showType({ firstName: "John" })
// Error: Object literal may only specify known properties, and 'firstName' does not exist in type 'Pick<PickType, "id">'

Omit 的工做方式與 Pick 相似。

Extract

  • Extract<T, U>

Extract 使你經過選擇出如今兩個不一樣類型中的屬性來構造類型。它從 T 中提取全部可分配給 U 的屬性。

interface FirstType {
  id: number
  firstName: string
  lastName: string
}

interface SecondType {
  id: number
  address: string
  city: string
}

type ExtractType = Extract<keyof FirstType, keyof SecondType>
// Output: "id"

在代碼中的兩個接口裏有共有的屬性 id。經過 Extract 能夠把 id 提取出來。若是你有多個共享字段,Extract 將會提取全部類似的屬性。

Exclude

Extract 不一樣,Exclude 經過排除已經存在於兩個不一樣類型中的屬性來構造類型。它排除了全部能夠分配給 U 的字段。

interface FirstType {
  id: number
  firstName: string
  lastName: string
}

interface SecondType {
  id: number
  address: string
  city: string
}

type ExcludeType = Exclude<keyof FirstType, keyof SecondType>

// Output; "firstName" | "lastName"

在上面的代碼中,屬性 firstNamelastName 可分配給 SecondType 類型,由於它們在那裏不存在。經過 Extract 能夠按預期返回這​​些字段。

Record

  • Record<K,T>

Record 能夠幫你構造一個類型,該類型具備給定類型 T 的一組屬性 K。當把一個類型的屬性映射到另外一個類型時,用 Record 很是方便。

interface EmployeeType {
  id: number
  fullname: string
  role: string
}

let employees: Record<number, EmployeeType> = {
  0: { id: 1, fullname: "John Doe", role: "Designer" },
  1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" },
  2: { id: 3, fullname: "Sara Duckson", role: "Developer" },
}

// 0: { id: 1, fullname: "John Doe", role: "Designer" },
// 1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" },
// 2: { id: 3, fullname: "Sara Duckson", role: "Developer" }

Record 的工做方式相對簡單。在代碼中,它指望用 number 做爲類型,這就是咱們把 0、1 和 2 做爲 employees 變量的鍵的緣由。若是試圖將字符串用做屬性,則會引起錯誤。接下來,屬性集由 EmployeeType 給出,所以該對象具備字段 idfullNamerole

NonNullable

  • NonNullable<T>

它容許你從類型 T 中刪除 nullundefined

type NonNullableType = string | number | null | undefined

function showType(args: NonNullable<NonNullableType>) {
  console.log(args)
}

showType("test")
// Output: "test"

showType(1)
// Output: 1

showType(null)
// Error: Argument of type 'null' is not assignable to parameter of type 'string | number'.

showType(undefined)
// Error: Argument of type 'undefined' is not assignable to parameter of type 'string | number'.

在代碼中吧 NonNullableType 做爲參數傳給了 NonNullableNonNullable 經過從該類型中排除 nullundefined 來構造新類型。也就是說,若是你傳遞可空的值,TypeScript 將會引起錯誤。

順便說一句,若是把 --strictNullChecks 標誌添加到 tsconfig 文件,TypeScript 將應用非空性規則。

映射類型

映射類型容許你獲取現有模型並將其每一個屬性轉換爲新類型。注意,前面介紹的一些實用工具類型也是映射類型。

type StringMap<T> = {
  [P in keyof T]: string
}

function showType(arg: StringMap<{ id: number; name: string }>) {
  console.log(arg)
}

showType({ id: 1, name: "Test" })
// Error: Type 'number' is not assignable to type 'string'.

showType({ id: "testId", name: "This is a Test" })
// Output: {id: "testId", name: "This is a Test"}

StringMap<> 會將傳入的任何類型轉換爲字符串。也就是說,若是在函數 showType() 中使用它,那麼接收到的參數必須是字符串,不然 TypeScript 將會報錯。

類型保護

類型保護使你能夠用運算符檢查變量或對象的類型。它其實是一個檢查用 typeofinstanceofin 所返回類型的條件塊。

  • typeof
function showType(x: number | string) {
  if (typeof x === "number") {
    return `The result is ${x + x}`
  }
  throw new Error(`This operation can't be done on a ${typeof x}`)
}

showType("I'm not a number")
// Error: This operation can't be done on a string

showType(7)
// Output: The result is 14

代碼中有一個普通的 JavaScript 條件塊,該塊檢查經過 typeof 檢測到的參數的類型。在這種狀況下就保護你的類型了。

  • instanceof
class Foo {
  bar() {
    return "Hello World"
  }
}

class Bar {
  baz = "123"
}

function showType(arg: Foo | Bar) {
  if (arg instanceof Foo) {
    console.log(arg.bar())
    return arg.bar()
  }

  throw new Error("The type is not supported")
}

showType(new Foo())
// Output: Hello World

showType(new Bar())
// Error: The type is not supported

和像前面的例子同樣,這也是一個類型保護,它檢查接收到的參數是否爲 Foo 類的一部分,並對其進行處理。

  • in
interface FirstType {
  x: number
}
interface SecondType {
  y: string
}

function showType(arg: FirstType | SecondType) {
  if ("x" in arg) {
    console.log(`The property ${arg.x} exists`)
    return `The property ${arg.x} exists`
  }
  throw new Error("This type is not expected")
}

showType({ x: 7 })
// Output: The property 7 exists

showType({ y: "ccc" })
// Error: This type is not expected

在代碼中,in 運算符用來檢查對象上是否存在屬性 x

Conditional 類型

用來對兩種類型進行測試,並根據測試的結果選擇其中的一種。

type NonNullable<T> = T extends null | undefined ? never : T

這個例子中的 NonNullable 檢查該類型是否爲 null 並根據該類型進行處理。

173382ede7319973.gif


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章


歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索