以下實(shí)用工具類(lèi)型適用于2.X及以上的typescript版本(為方便直觀的看出結(jié)果近上,下面配置為嚴(yán)格模式贵试,當(dāng)出現(xiàn)問(wèn)題時(shí)編譯不通過(guò)歌粥,直接報(bào)錯(cuò))
Partial<T>
構(gòu)造類(lèi)型T沮脖,并將它所有的屬性設(shè)置為可選的癞季。它的返回類(lèi)型表示輸入類(lèi)型的所有子類(lèi)型劫瞳,T一般為對(duì)象(ps:對(duì)象才有用到此方法的意義,其他簡(jiǎn)單類(lèi)型沒(méi)有使用他沒(méi)有什么意義)
type Partial<T> = { [P in keyof T]?: T[P] | undefined; }
import React, { Component } from 'react';
interface Interface {
a: number;
b: number;
}
export default class PartialInfo extends Component {
render() {
// 變量類(lèi)型為對(duì)象
// 正確顯示值
const partial1: Partial<Interface> = {};
const partial2: Partial<Interface> = {
a: 1
};
const partial3: Partial<Interface> = {
a: 1,
b: 1
};
// 不屬于Interface的key值
const partial4: Partial<Interface> = {
// 不能將類(lèi)型“{ c: number; }”分配給類(lèi)型“Partial<Interface>”绷柒。
// 對(duì)象文字可以只指定已知屬性志于,并且“c”不在類(lèi)型“Partial<Interface>”中。
c: 1 // ?
};
// 變量類(lèi)型為string(無(wú)具體意義废睦,僅證明可以輸入)
// Partial<T>中的T可以是任意類(lèi)型不必拘泥于對(duì)象
const partial5: Partial<string> = '';
console.log(partial1, partial2, partial3, partial4, partial5);
return (
<div>Partial</div>
);
}
}
使用場(chǎng)景
- interfaceA與 interfaceB 在代碼中同時(shí)會(huì)被【使用】伺绽,并且interfaceB需要屬性, interfaceA中全部存在(interfaceA與 interfaceB 在代碼中同時(shí)會(huì)被【使用】嗜湃,并且interfaceB需要屬性奈应, interfaceA中全部存在)
- eg:對(duì)表格進(jìn)行篩選,篩選條件的類(lèi)型可為Partial<T>
- eg:
// 賬號(hào)屬性
interface AccountInfo { name: string email: string age: number vip: 0|1 // 1 是vip 购披,0 是非vip }
// 當(dāng)我們需要渲染一個(gè)賬號(hào)表格時(shí)杖挣,我們需要定義
const accountList: AccountInfo[] = []
// 但當(dāng)我們需要查詢(xún)過(guò)濾賬號(hào)信息,需要通過(guò)表單刚陡,
// 但明顯我們可能并不一定需要用到所有屬性進(jìn)行搜索惩妇,此時(shí)可以定義
const model: Partial<AccountInfo> = { name: '', vip: undefind }
Readonly<T>
構(gòu)造類(lèi)型T,并將它所有的屬性設(shè)置為readonly筐乳,也就是說(shuō)構(gòu)造出的類(lèi)型的屬性不能被再次賦值歌殃。
import React, { Component } from 'react';
interface Todo {
title: string;
}
export default class ReadonlyInfo extends Component {
// 對(duì)象
todo: Readonly<Todo> = {
title: 'one',
};
this.todo.title = 'Hello';
render() {
// 對(duì)象
console.log('todo', this.todo);
return (
<div>Readonly</div>
);
}
}
string1: Readonly<string> = '234';
this.string1 = '34';
Object.freeze
方法可以?xún)鼋Y(jié)一個(gè)對(duì)象。一個(gè)被凍結(jié)的對(duì)象再也不能被修改蝙云;凍結(jié)了一個(gè)對(duì)象則不能向這個(gè)對(duì)象添加新的屬性氓皱,不能刪除已有屬性,不能修改該對(duì)象已有屬性的可枚舉性勃刨、可配置性波材、可寫(xiě)性,以及不能修改已有屬性的值身隐⊥⑶【此外,凍結(jié)一個(gè)對(duì)象后該對(duì)象的原型也不能被修改抡医《阋颍】??【不寫(xiě)進(jìn)ppt】??freeze()返回和傳入的參數(shù)相同的對(duì)象早敬。
import React, { Component } from 'react';
interface Todo {
title: string;
}
export default class FreezeInfo extends Component {
// 對(duì)象
todo = {
title: 'one'
};
freezeObj = (todo: Todo) => {
Object.freeze(todo);
todo.value = '1';
console.log('todo', todo)
}
render() {
// 對(duì)象
this.freezeObj(this.todo)
return (
<div>freeze</div>
);
}
}
Object.freeze僅對(duì)對(duì)象起作用忌傻,對(duì)其他類(lèi)型不起作用(包括數(shù)組)
freezeString = (todo: string) => {
Object.freeze(todo);
todo = '1';
console.log('todo', todo)
}
this.freezeObj(this.todo)
Record<K,T>
構(gòu)造一個(gè)類(lèi)型,其屬性名的類(lèi)型為K搞监,屬性值的類(lèi)型為T(mén)水孩。將某個(gè)類(lèi)型的屬性映射到另一個(gè)類(lèi)型上,當(dāng)K為某些固定值而非范圍性類(lèi)型時(shí),需要全部映射,定義的屬性名類(lèi)型必須全部都有琐驴,屬性值看是否可選
K的類(lèi)型為number | string | symbol
type Record<K extends string | number | symbol, T> = { [P in K]: T; }
import React, { Component } from 'react';
interface PageInfo {
a: number;
b?: number;
}
type Page = 'key1' | 'key2' | 'key3';
type PageIn = number | string;
export default class RecordInfo extends Component {
render() {
// 屬性名為具體值
const page1: Record<Page, PageInfo> = {
key1: { a: 1, b: 2 },
key2: { a: 1 },
key3: { a: 1 },
};
// 屬性名為類(lèi)型范圍值
// 此處屬性名類(lèi)型K中使用的是固定的變量俘种,也可以使用入number秤标、string等的范圍性類(lèi)型,那么此刻屬性名隨意宙刘、個(gè)數(shù)隨意
const page2: Record<PageIn, PageInfo> = {
1: { a: 1, b: 2 },
2: { a: 1, b: 2 },
key1: { a: 1 },
key2: { a: 1 },
};
console.log(page1, page2)
return (
<div>Partial</div>
);
}
}
Pick<T,K>
從類(lèi)型T中挑選部分屬性K來(lái)構(gòu)造類(lèi)型苍姜。T中必須包含K中的所有屬性,K中的屬性悬包,必須在對(duì)象中全部擁有(ps衙猪,T中可以只有K中的屬性)
import React, { Component } from 'react';
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, 'title' | 'completed'>;
export default class PickInfo extends Component {
// 對(duì)象
todo: TodoPreview = {
title: 'Clean room',
completed: false,
};
render() {
console.log('todo', this.todo)
return (
<div>Pick</div>
);
}
}
Exclude<T,U>
從類(lèi)型T中剔除所有可以賦值給U的屬性,然后構(gòu)造一個(gè)類(lèi)型布近。允許T中沒(méi)有U屬性的情況存在
type Exclude<T, U> = T extends U ? never : T
import React, { Component } from 'react';
interface Obj1 {
a: string;
b: number;
}
interface Obj2 {
a: string;
b: number;
c: string;
}
interface Obj3 {
b: string;
c: number;
}
interface Obj4 {
a: string;
b: string;
c: string;
}
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
type T2 = Exclude<string | number | (() => void), Function>; // string | number
type T3 = Exclude<Obj1 | Obj2 | Obj3, Obj1>; // Obj3
type T4 = Exclude<Obj1 | Obj4 | Obj3, Obj1>; // Obj4 | Obj3
export default class ExcludeInfo extends Component {
render() {
return (
<div>Exclude</div>
);
}
}
- () => void與Function為何換了位置垫释,結(jié)果就完全不同了,參見(jiàn)上篇【類(lèi)型】中的函數(shù)賦值
- type T3 = Extract<Obj1 | Obj2 | Obj3, Obj1>; // 值為Obj1 | Obj2原因撑瞧,參見(jiàn)上篇【類(lèi)型】中的對(duì)象賦值
使用場(chǎng)景
interface的信息與其他interface有關(guān)棵譬,會(huì)隨著其他的interface變化而變化
Extract<T,U>
從類(lèi)型T中提取所有可以賦值給U的類(lèi)型,然后構(gòu)造一個(gè)類(lèi)型预伺。簡(jiǎn)而言之就是T订咸、U中有相同的部分,就提取出來(lái)扭屁,作為類(lèi)型值
type Extract<T, U> = T extends U ? T : never
import React, { Component } from 'react';
interface Obj1 {
a: string;
b: number;
}
interface Obj2 {
a: string;
b: number;
c: string;
}
interface Obj3 {
b: string;
c: number;
}
interface Obj4 {
a: string;
b: string;
c: string;
}
type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T1 = Extract<string | number | (() => void), Function>; // () => void
type T2 = Extract<string | number | Function, (() => void)>; // never
type T3 = Extract<Obj1 | Obj2 | Obj3, Obj1>; // Obj1 | Obj2
type T4 = Extract<Obj1 | Obj4 | Obj3, Obj1>; // Obj1
export default class ExtractInfo extends Component {
render() {
return (
<div>Extract</div>
);
}
}
- () => void與Function為何換了位置算谈,結(jié)果就完全不同了,參見(jiàn)上篇【類(lèi)型】中的函數(shù)賦值
- type T3 = Extract<Obj1 | Obj2 | Obj3, Obj1>; // 值為Obj1 | Obj2原因料滥,參見(jiàn)上篇【類(lèi)型】中的對(duì)象賦值
使用場(chǎng)景
interface的信息與其他interface有關(guān)然眼,會(huì)隨著其他的interface變化而變化
NonNullable<T>
從類(lèi)型T中剔除null和undefined,然后構(gòu)造一個(gè)類(lèi)型葵腹。
type T0 = NonNullable<string | number | undefined>; // string | number
type T1 = NonNullable<string[] | null | undefined>; // string[]
ReturnType<T>
由函數(shù)類(lèi)型T的返回值類(lèi)型構(gòu)造一個(gè)類(lèi)型高每。
import React, { Component } from 'react';
const f1 = () => {
return {
a: 1,
b: 'string'
}
}
type T0 = ReturnType<() => string>; // string
type T1 = ReturnType<(s: string) => void>; // void
type T2 = ReturnType<(<T>() => T)>; // unknown
type T3 = ReturnType<(<T extends U, U extends number[]>() => T)>; // number[]
type T4 = ReturnType<typeof f1>; // { a: number, b: string }
export default class ReturnTypeInfo extends Component {
b:T7 = 6;
render() {
let a:T2 = 3;
a = '3';
console.log('a', a)
console.log('b', this.b)
return (
<div>ReturnType</div>
);
}
}
當(dāng)返回的值為unknown時(shí),就代表他是任意值践宴,你可以給此類(lèi)型的參數(shù)賦給任意值鲸匿,不會(huì)報(bào)錯(cuò),但并不代表他不進(jìn)行編譯了阻肩,它相當(dāng)于一個(gè){},任何對(duì)象都屬于這個(gè){}带欢,所以賦為任何值都不會(huì)報(bào)錯(cuò)。
有兩個(gè)特殊的值烤惊,一個(gè)為any乔煞,另一個(gè)為never,分別為柒室,編譯時(shí)略過(guò)檢查渡贾,和不存在一個(gè)值滿(mǎn)足當(dāng)前條件,這兩個(gè)值作為參數(shù)傳入,默認(rèn)是不報(bào)錯(cuò)的
type T5 = ReturnType<any>; // any
type T6 = ReturnType<never>; // never
ReturnType接收的參數(shù)T必須為一個(gè)函數(shù)類(lèi)型雄右,傳入其他類(lèi)型值時(shí)報(bào)錯(cuò)空骚,當(dāng)T為Function時(shí)報(bào)錯(cuò)纺讲。
type T7 = ReturnType<string>; // Error
type T8 = ReturnType<Function>; // Error
用一種簡(jiǎn)單的思維去思考為什么Function不能傳入,回歸到定義本身【由函數(shù)類(lèi)型T的返回值類(lèi)型構(gòu)造一個(gè)類(lèi)型囤屹“旧酰】,如果Function沒(méi)有返回值肋坚,要怎么辦呢则涯?是不是這么一問(wèn)就直接能解決上文為何Function作為傳入值報(bào)錯(cuò)
Required<T>
構(gòu)造一個(gè)類(lèi)型,使類(lèi)型T的所有屬性為required冲簿。即便在interface中寫(xiě)的是可選類(lèi)型粟判,但如果使用了Required,那么所有的屬性都變成必須的峦剔,沒(méi)有例外
import React, { Component } from 'react';
interface Obj {
a?: number;
b?: string;
};
export default class RequiredInfo extends Component {
render() {
const obj1: Obj = { a: 5 }; // OK
const obj2: Required<Obj> = { a: 5 }; // Error: property 'b' missing
console.log('obj1', obj1);
console.log('obj2', obj2);
return (
<div>Required</div>
);
}
}