TS-高級(jí)類型

  • 類型保護(hù)(Type Guards)
  • 可空類型(Nullable types)
  • 類型別名(Type Aliases)
  • 多態(tài)this
  • 索引類型
  • 映射類型
  • 條件類型
  • TS庫(kù)中的內(nèi)置類型轉(zhuǎn)換實(shí)用類型

1.類型保護(hù)(Type Guards)

類型保護(hù)就是確保該類型在一定的范圍內(nèi)可以運(yùn)行叫榕,簡(jiǎn)單來說就是當(dāng)一個(gè)值為number類型或者string類型怖辆,類型保護(hù)就是當(dāng)它為number類型時(shí)確保它的值為number散址,當(dāng)它為string類型時(shí)確保它的值為sting
實(shí)現(xiàn)類型保護(hù)常用的有幾下幾種方法

  • in
  • instanceof
  • typeof
  • 自定義類型
class Bird {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  fly() {
    console.log("fly")
  }
}
class Fish {
  name: string;
  constructor(name: string){
    this.name = name;
  }
  swim(){
    console.log("swim")
  }
}
declare function getSmallPet(): Fish | Bird;
let pet = getSmallPet();
pet.name;
pet.swim(); //error 類型“Fish | Bird”上不存在屬性“swim”

如上充石,假如當(dāng)前pet確實(shí)是Fish類型的,我們想用到swim方法域庇,我們就可以使用類型保護(hù)來確保typescript識(shí)別他的具體類型;
注: 當(dāng)然我們可以使用類型斷言 as烁兰,但是這不是我們想要的

使用 in
 if("swim" in pet){
  pet.swim();  //ok
}
使用 instanceof
if(pet instanceof Fish){
  pet.swim() //ok
}
使用 typeof

注: typeof 只能判斷該類型的基本類型脚囊,如"string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"

function getSum(arg: number | string): number{
  if(typeof arg === "number"){
    return arg++
  }else{
    return parseInt(arg) + 1
  }
}
自定義的類型保護(hù)
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}
if(isFish(pet)){
  pet.swim();
}

2.可空類型(Nullable types)

TypeScript有兩個(gè)特殊類型,null和undefined

let num: number | undefined = 123;
let obj: object | null = {};

// 此時(shí)求和就可以使用類型保護(hù)來避免出現(xiàn)錯(cuò)誤
function getSum(){
  if(typeof num === 'number'){
    num++
  }
}

3. 類型別名(Type Aliases)

類型別名即為類型創(chuàng)建新名稱芦拿。比如為我們的接口數(shù)據(jù)定義一個(gè)類型Result:

type Result<T> ={
  code: number;
  data: T,
  message: string
}

此時(shí)的Result即為類型別名

4.多態(tài)this

多態(tài)this類型是某個(gè)包含的類或接口的子類型;
this類型它能表現(xiàn)連貫接口間的繼承簡(jiǎn)易性

class Base {
  constructor(
    public value: number 
  ){}

  add(num: number): this{
    this.value += num;
    return this;
  }

  multiply(num: number): this {
    this.value *= num;
    return this;
  }
}

let a = new BaseCalculator(3);
a.add(7).multiply(5).add(5).value;//鏈?zhǔn)?

使用this類型士飒,可以對(duì)其進(jìn)行擴(kuò)展查邢,并且新類可以使用舊類方法

//類可以拓展
class Child extends Base {
  constructor(value: number = 0){
    super(value);
  }
  public sin() {
    this.value = Math.sin(this.value);
    return this;
  }
}
let b = new ScientificCalculator();
b.sin().add(1).multiply(4).value;

5.索引類型

索引類型即可被索引的類型,對(duì)應(yīng)JavaScript 中的數(shù)組酵幕、對(duì)象等聚合多個(gè)元素的類型扰藕。
keyof 為常用的索引查詢運(yùn)算符
比如: 我們想獲取某個(gè)對(duì)象中某個(gè)屬性值

function getProperty<T, K extends keyof T>(o: T, propertyName: K): T[K] {
  return o[propertyName]; 
}

interface People {
  name: string;
  age: number;
  say(): void;
}
let li: People = {
  name: "li",
  age: 18,
  say(){
    console.log("i am li")
  }
}
const  liName = getProperty(li,"name");

6.映射類型

即類型可以映射,常用于基于舊類型創(chuàng)建新類型芳撒;
TS庫(kù)中已內(nèi)置映射方法有Partial实胸,Readonly, Pick, Record
注:
Partial,Readonly, Pick為同態(tài)番官,即不會(huì)創(chuàng)建新屬性 添加新成員只能用&
Record為非同態(tài)庐完,即會(huì)創(chuàng)建新屬性, 新屬性由Record第一個(gè)屬性指定

//將某類型全部變?yōu)榭蛇x屬性
type Partial<T> = {
  [P in keyof T]?: T[P];
};
//將某類型變?yōu)閞eadonly類型
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};
//抽取目標(biāo)類型的子集類型
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};
//非同態(tài): 會(huì)創(chuàng)建新屬性, 新屬性由Record第一個(gè)屬性指定
type Record<K extends keyof any, T> = {
  [P in K]: T;
};
//eg:
interface People{
  name: string,
  age: number,
  sex: string
}
type PartialMan = Partial<People>;//Partial
type ReadonlyMan = Readonly<People>;//Readonly
type PickMan = Pick<People, "name" | "age">;//Pick

let PartialLilei: PartialMan = {
  name: "lilei",
  age: 18
}
let PickLilei: PickMan = {
  name: 'lilei',
  age: 18
}

//同態(tài)添加新成員只能用&
type Woman=  Readonly<People> & { say(): void};

//Record
enum method {
  Get= 'get',
  // Post= 'post',
  // Delete= 'delete'
};
interface HttpFn {
  (url: string, config?: any) : Promise<void>
}
type RecordHttp = Record<method, HttpFn>;

let httpget: RecordHttp = {
  get: (url: string, config?: any) => {
      //return new Promise((reslove,reject) => {
      //reslove()
      //})
  },
  post:(url: string, config?: any) => {
      //return new Promise((reslove,reject) => {
      //reslove()
      //})
  }
}

7 條件類型

根據(jù)條件判斷來推測(cè)其類型。常用表達(dá)式為:

T extends U ? X : Y;

上面表達(dá)式含義為:若 T 能夠分配(賦值)給 U(即是U的子類型)徘熔,那么類型是 X门躯,否則為 Y

type value<T> = T extends boolean ? string : number;
let val:  value<false> = "123";//ok
let val: value<true> = 123; //error

條件延時(shí)推測(cè)---即當(dāng)推測(cè)條件不足時(shí),會(huì)推遲條件判斷酷师,直至條件充足時(shí)讶凉;

interface Foo {
    propA: boolean;
    propB: boolean;
}

declare function f<T>(x: T): T extends Foo ? string : number;

function foo<U>(x: U) {
     // 因?yàn)?”x“ 未知,因此判斷條件不足山孔,不能確定條件分支懂讯,推遲條件判斷直到 ”x“ 明確,
    // 推遲過程中台颠,”a“ 的類型為分支條件類型組成的聯(lián)合類型褐望,string | number 聯(lián)合類型
    let a = f(x);
    // 這么做是完全可以的
    let b: string | number = a;
}
分布條件類型

即:其中選中的類型為裸類型參數(shù)的條件類型稱為分布式條件類型;例化期間串前,分布條件類型自動(dòng)分布在聯(lián)合類型上瘫里。例如,T extends U ? X : Y使用類型參數(shù)A | B | Cfor的實(shí)例化T解析為(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)荡碾。
注: 裸類型為 類型參數(shù)沒有被包裝在其他類型里,比如沒有被數(shù)組谨读、元組、函數(shù)坛吁、Promise,對(duì)象等包裹
如:

// 裸類型,沒有被任何其他類型包裹劳殖,即T
type NakedType<T> = T extends boolean ? "YES" : "NO"
// 非裸類型,類型參數(shù)被包裹的在元組內(nèi)拨脉,即[T]
type WrappedType<T> = [T] extends [boolean] ? "YES" : "NO";

條件類型的分布屬性可以方便地用于過濾聯(lián)合類型:

//過濾聯(lián)合類型中的null和undefined哆姻,
type NonNullable<T> = T extends null | undefined ? never : T
//never 類型表示不會(huì)是任何值,即什么都沒有

type a = string | number| Function | null | undefined;
let b: NotNullable<a>  = 1;//ok
b = null; //error
條件類型與映射類型

條件類型和映射類型配合使用特別有用

//提取類型中屬性值為Funtion類型key值,相當(dāng)于 {key: key | never}[key]
type FunctionPropertyNames<T> = {
  [K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];

//FunctionPropertyNames<T>為key值,Pick是提取屬性值為FunctionPropertyNames<T>的值女坑,相當(dāng)于{key: T[key]}
type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>;

//提取類型中屬性值不為Funtion類型key值,相當(dāng)于 {key: key | never}[key]
type NonFunctionPropertyNames<T> = {
  [K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];

type NonFunctionProperties<T> = Pick<T, NonFunctionPropertyNames<T>>;

interface Part {
  id: number;
  name: string;
  subparts: Part[];
  updatePart(newName: string): void;
}

type T1 = FunctionPropertyNames<Part>;
//type T1 = "updatePart"

type T2 = FunctionProperties<Part>;
// type T3 = {
//       updatePart: (newName: string) => void;
//   }

type T3 = NonFunctionPropertyNames<Part>;
// type T2 = "id" | "name" | "subparts"

type T4 = NonFunctionProperties<Part>;
// type T4 = {
//       id: number;
//       name: string;
//       subparts: Part[];
//   }

8 TS庫(kù)中的內(nèi)置類型轉(zhuǎn)換實(shí)用類型

1. Partial<Type>  //將某類型全部變?yōu)榭蛇x屬性填具,前面已介紹
2. Readonly<Type> //將某類型全部變?yōu)镽eadonly屬性,前面已介紹
3. Pick<Type, Keys> //抽取目標(biāo)類型的子集類型,前面已介紹
3. Record<Keys,Type> //非同態(tài): 會(huì)創(chuàng)建新屬性, 新屬性由Record第一個(gè)屬性指定 劳景,前面已介紹
4. Omit<Type, Keys> //移除某一類型中的屬性
interface People{
  name: string,
  age: number,
  sex: string,
  height: number
}
type Man = Omit<People, 'height'>
/*
 { name: string,
  age: number,
  sex: string
}
*/
5. Exclude<Type, ExcludedUnion>//去除聯(lián)合類型中指定類型
type T0 = Exclude<"a" | "b" | "c" | "d","a" | "b">;
// type T0 = "c" | "d"誉简;
6. Extract<Type, Union>//返回聯(lián)合類型中相同類型
type T0 = Exclude<"a" | "b" | "c" | "d","a" | "f">;
// type T0 = "a";
7. NonNullable<Type>//去除類型中null和undefined盟广;
type T1 = NonNullable<string[] | string | null | undefined>;
// type T1 = string[] | string;
8. Parameters<Type>//提取函數(shù)類型中參數(shù)類型闷串,返回參數(shù)類型元祖,非函數(shù)返回unkown
type T0 = Parameters<() => string>;
// type T0 = []
type T1 = Parameters<(s: string) => void>;
// type T1 = [s: string]
type T2 = Parameters<any>;
// type T2 = unknown[]
type T3 = Parameters<never>;
// type T2 = never
9. ConstructorParameters<Type>//返回構(gòu)造函數(shù)中Constructor參數(shù)元組
type T0 = ConstructorParameters<ErrorConstructor>;
// type T0 = [message?: string]
type T1 = ConstructorParameters<FunctionConstructor>;
// type T1 = string[]
type T2 = ConstructorParameters<RegExpConstructor>;
// type T2 = [pattern: string | RegExp, flags?: string]
type T3 = ConstructorParameters<any>;
// type T3 = unknown[]
10. ReturnType<Type>//返回函數(shù)的返回類型組成的類型筋量。
type T0 = ReturnType<() => string>;
//type T0 = string
type T1 = ReturnType<(s: string) => void>;
//type T1 = void
type T2 = ReturnType<<T>() => T>;
// type T2 = unknown

11. InstanceType<Type>//返回構(gòu)造函數(shù)的實(shí)例類型組成的類型
class C {
  x = 0;
  y = 0;
}
type T0 = InstanceType<typeof C>;
//type T0 = C
type T1 = InstanceType<any>;
// type T1 = any
type T2 = InstanceType<never>;
//type T2 = never

12. Required<Type>//與Partial相反烹吵,將類型中可選參數(shù)變?yōu)楸剡x
interface Props {
  a?: number;
  b?: string;
}
const obj: Required<Props>;
//obj: {
// a: number;
 // b: string;
//}

13.ThisParameterType<Type>//獲取函數(shù)中 this的數(shù)據(jù)類型,如果沒有則返回 unknown 類型
function toHex(this: Number) {
  return this.toString(16);
}

function numberToString(n: ThisParameterType<typeof toHex>) {
  return toHex.apply(n);
}

14.OmitThisParameter<Type>//移除函數(shù)中的 this 數(shù)據(jù)類型:
function toHex(this: Number) {
  return this.toString(16);
}
const fiveToHex: OmitThisParameter<typeof toHex> = toHex.bind(5);
console.log(fiveToHex());

15.ThisType<Type>//該實(shí)用程序不返回轉(zhuǎn)換后的類型桨武。相反肋拔,它用作上下文this類型的標(biāo)記。請(qǐng)注意呀酸,--noImplicitThis必須啟用該標(biāo)志才能使用此實(shí)用程序
type ObjectDescriptor<D, M> = {
  data?: D;
  methods?: M & ThisType<D & M>; // Type of 'this' in methods is D & M
};
function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
  let data: object = desc.data || {};
  let methods: object = desc.methods || {};
  return { ...data, ...methods } as D & M;
}
let obj = makeObject({
  data: { x: 0, y: 0 },
  methods: {
    moveBy(dx: number, dy: number) {
      this.x += dx; // Strongly typed this
      this.y += dy; // Strongly typed this
    },
  },
});
obj.x = 10;
obj.y = 20;
obj.moveBy(5, 5);
//在上面的例子中凉蜂,`methods`在參數(shù)對(duì)象`makeObject`具有上下文類型,其包括`ThisType<D & M>`和因此的類型[此](https://www.typescriptlang.org/docs/handbook/functions.html#this)內(nèi)的方法`methods`目的是`{ x: number, y: number } & { moveBy(dx: number, dy: number): number }`性誉。請(qǐng)注意窿吩,`methods`屬性的類型如何同時(shí)成為`this`方法中類型的推斷目標(biāo)和來源。

//該`ThisType<T>`標(biāo)記接口是簡(jiǎn)單地宣布一個(gè)空的接口`lib.d.ts`错览。除了在對(duì)象文字的上下文類型中被識(shí)別之外纫雁,該接口的作用類似于任何空接口。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末倾哺,一起剝皮案震驚了整個(gè)濱河市轧邪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌悼粮,老刑警劉巖闲勺,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異扣猫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)翘地,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門申尤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人衙耕,你說我怎么就攤上這事昧穿。” “怎么了橙喘?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵时鸵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)饰潜,這世上最難降的妖魔是什么初坠? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮彭雾,結(jié)果婚禮上碟刺,老公的妹妹穿的比我還像新娘。我一直安慰自己薯酝,他們只是感情好半沽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吴菠,像睡著了一般者填。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上做葵,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天占哟,我揣著相機(jī)與錄音,去河邊找鬼蜂挪。 笑死重挑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的棠涮。 我是一名探鬼主播谬哀,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼严肪!你這毒婦竟也來了史煎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤驳糯,失蹤者是張志新(化名)和其女友劉穎篇梭,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酝枢,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡恬偷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帘睦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袍患。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖竣付,靈堂內(nèi)的尸體忽然破棺而出诡延,到底是詐尸還是另有隱情,我是刑警寧澤古胆,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布肆良,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏惹恃。R本人自食惡果不足惜夭谤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望座舍。 院中可真熱鬧沮翔,春花似錦、人聲如沸曲秉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)承二。三九已至榆鼠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間亥鸠,已是汗流浹背妆够。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留负蚊,地道東北人神妹。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像家妆,于是被迫代替她去往敵國(guó)和親鸵荠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容