這篇文章講解類型
。莫要讓 TypeScript
成爲 AnyScript
,學習類型也是從簡單
到複雜
。typescript
T
表示 type 類型P
表示 props 屬性K/V
key/valueU
經常使用的類型變量複雜類型中經常使用的關鍵字和操做符json
keyof
至關於 Object.keysin
至關於 for-in?
可選操做符-?
可選取反extends
interface/class
表示繼承type
中表示約束[]
定義函數的輸入和輸出api
爲了更好的使用 TypeScript, 須要開啓嚴格的 TypeScript 代碼檢查:markdown
noImplicitAny
沒有隱式的 any 類型推斷
strictNullChecks
嚴格的 null 檢查
{
"compilerOptions": {
"noImplicitAny": true,
"strictNullChecks": true,
}
}
複製代碼
嚴格的 null 檢查 最佳實踐1 , 在處理空指針的狀況下,很是實用。app
type User = {
name: string;
age?: number; // 可選的屬性,不存在時,不能使用其上面的屬性和方法
}
const getUser = (user: User) => {
console.log(user.name, user.age.toString()) // user.age 🐛 可能不存在可是調用方法
}
複製代碼
age 是可選的,可是在 console.log 中調用了 toString 方法。dom
?.
來解決這個🐛,嚴格檢查console.log(user.name, user.age?.toString())
複製代碼
any[]
類型type
引出接口 interface
在 TypeScript 中,使用 type 關鍵字,定義類型別名函數
type User = number | string; // 定義 number | string 的聯合類型爲 User
複製代碼
⚠️:別名 type 一旦定義定義就不能擴展本身
,只能用 type
定一個其餘的類型。基於別名 type 自生不可擴展,引出 接口 interface 的概念就很合適了。oop
interface Global {
api1: number
}
複製代碼
咱們想要擴展 Global 接口,就能夠直接從新定義(從新定義不是簡單的覆蓋行爲)學習
interface Global {
api2: number
}
複製代碼
api2接口屬性是補充在 Global 屬性上面的,而不是覆蓋以前定義的 api1。ui
對象類型應該是咱們最經常使用的複合類型在之一了。
他們的最主要的區別之一就是:能不能不產生新的類型
的基礎上擴展本身。
?.<your option>
readonly <you option>
有時候,咱們不肯定屬性的名稱,此時咱們就能夠定義索引類型
interface User {
[index: string]: any
}
複製代碼
index
表示索引,索引的類型是 string,屬性對應的類型是 any
不產生
一個新的接口產生
一個新的接口|
聯合類型,進行擴展,產生
一個新的類型。兩個類型交叉,將兩個不一樣類型組合成一個新的類型沒有重複
的新的類型
type A = {
name: string
age: number
}
type B = {
age: number
sex: string
}
const C: A & B = {
name: 'sdfd',
age: 123,
sex: 'male'
}
const D: A | B = {
name: 'sdf',
age: 123
}
複製代碼
重要
的條件類型extends
約束類型extends關鍵字,在類型約束
中起到重要做用。
SomeType extends OtherType ? TrueType : FalseType;
複製代碼
extends
關鍵字,本質是遍歷,每個屬性對比是子集,返回 TrueType
, 不然返回 FalseType
。 extends 表示條件? :
, 分配類型泛條件類型
。本質很簡單,就是將是三目運算符,放在了類型的判斷中:(一個前提:條件是繼承關係)
T extends U ? X : Y
複製代碼
也就是說 子類型 T
是否是繼承自父類型 U
,若是是
,取 X 類型,若是不是
取 Y 類型。
既然是條件,那有 true/false 就很正常
type User = {
name: string;
age: number
}
declare function <T extends boolean>f(x: T): T extends true ? User : null;
// T 類型繼承 true 類型時,函數 f 的返回值是 User, 不然是 null
const a = f(Math.random() < 0.1); // User | number
const b = f( 1 < 2) // User
const c = f( 1 > 2) // null
複製代碼
關於範型,這裏不討論。
type Exclude<T, U> = T extends U ? never : T;
複製代碼
type Ex<T, U> = T extends U ? never : T
type Parent = {
name: string;
age: number;
}
type User = {
name: string;
age: number;
sex: string;
}
// A 是 User 類型, 下面的 sex 的存在
const A: Ex<User, Parent> = {
name: 'xiaoming',
age: 234,
sex: 'sdf' // Type '{ name: string; age: number; pa: number; ad: number; sex: string; }' is not assignable to type 'User'.
}
複製代碼
A
是 Ex<User, Parent> 類型,Parent
類型,不是 extends
User
,因此得 A
就是 User
類型.
type IId = { id: number }
type IName = { name: string }
type NameOrId<T extends string | number> = T extends number ? IId : IIName
複製代碼
從上面看了 Exclude 的源碼,是 子集 + never
, 由此,咱們也能擴展其餘的類型:
子集 + null
子集 + undefined
子集 + any
(好像沒有必要)type CNull<T, U> = T extends U ? null : T;
type CUndefined<T, U> = T extends U ? undefined : T;
type CAnd<T, U> = T extends U ? and : T;
複製代碼