TypeScript的核心原則之一是對值所具有的結(jié)構(gòu)進(jìn)行類型檢查
泛型
泛型是指一個表示類型的變量溯祸,一般用T表示,用它來代替某個實(shí)際的類型本姥,而后通過實(shí)際調(diào)用時傳入的類型來對其進(jìn)行替換肩袍,可以利用泛型來適應(yīng)不同類型。
TypeScript 中不建議使用 any 類型婚惫,不能保證類型安全氛赐,調(diào)試時缺乏完整的信息。
TypeScript可以使用泛型來創(chuàng)建可重用的組件先舷。支持當(dāng)前數(shù)據(jù)類型艰管,同時也能支持未來的數(shù)據(jù)類型。擴(kuò)展靈活蒋川∩螅可以在編譯時發(fā)現(xiàn)你的類型錯誤,從而保證類型安全尔破。
1:泛型函數(shù)
<泛型變量名稱>(參數(shù)1: 泛型變量, 參數(shù)2: 泛型變量, ...參數(shù)n: 泛型變量) => 泛型變量
/*------------基礎(chǔ)使用方法------------*/
function join<T, P>(first: T, second: P): T {
return first;
}
//const twoParms = join<number, string>(1, '我是string');
const twoParms = join(1, '我是string');
/*---------泛型集合--------------*/
function map<T>(params: Array<T>) {
return params;
}
//const sanleType = map<string>(['123']);
const sanleType = map(['123']);
/* -----------泛型箭頭函數(shù)-------------*/
const identity = <T,>(arg: T): T => {
return arg;
};
const identity2: <T>(arg: T) => T = (arg) => {
return arg;
};
2:泛型接口
/* -------------泛型接口-------------*/
interface ColumnProps<T> {
key: number | string;
title: string;
dataIndex: keyof T; // 約束 dataIndex 值需為引用泛型 T 中的屬性
}
interface ITableItem {
key: number | string;
name: string;
address: string;
age: number;
}
const columns: Array<ColumnProps<ITableItem>> = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
];
3:泛型類
/*--------------泛型類---------------*/
class Person<T> {
love: T;
say: (arg: T) => T;
}
let myFn: IGeneric<number> = fn;
myFn(13); //13
let me = new Person<string>();
me.love = 'TS';
// me.love = 520; // ERROR
me.say = function(love: string){
return `my love is ${love}`;
}
泛型約束
泛型可以通過 extends 一個接口來實(shí)現(xiàn)泛型約束街图,寫法如:
<泛型變量 extends 接口>
<T, K extends keyof T>
//K為傳入的T上已知的屬性,
interface IArray {
length: number
}
function logIndex<T extends IArray>(arg: T): void {
for (let i = 0; i < arg.length; ++i) {
console.log(i)
}
}
let arr = [1, 2, 3]
// logIndex<number>(arr) // 報(bào)錯
logIndex<number[]>(arr) // 允許
logIndex(arr) // 自動類型推導(dǎo)懒构,允許
泛型應(yīng)用場景之一
/*-------------應(yīng)用場景start---------------------------*/
interface ColumnProps<T> {
key: number | string;
title: string;
dataIndex: keyof T; // 約束 dataIndex 值需為引用泛型 T 中的屬性
}
interface ITableItem {
key: number | string;
name: string;
address: string;
age: number;
}
interface TableProps {
dataSource: ITableItem[];
columns: Array<ColumnProps<ITableItem>>;
}
const MyTable = (props: TableProps) => {
const { dataSource, columns } = props;
return <Table dataSource={dataSource} columns={columns} />;
};
const ApplcationMod = () => {
const dataSource = [
{
key: '1',
name: '金城武',
age: 32,
address: '西湖區(qū)湖底公園1號',
},
{
key: '2',
name: '吳彥祖',
age: 42,
address: '西湖區(qū)湖底公園1號',
},
];
const columns: Array<ColumnProps<ITableItem>> = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年齡',
dataIndex: 'age',
key: 'age',
},
{
title: '住址',
dataIndex: 'address',
key: 'address',
},
];
return (
<div>
<h3>泛型應(yīng)用場景</h3>
<MyTable dataSource={dataSource} columns={columns} />
</div>
);
};
keyof 關(guān)鍵字
keyof 關(guān)鍵字非常實(shí)用,后面可以看到很多工具泛型都是使用 keyof 實(shí)現(xiàn)的耘擂。
keyof T(索引類型查詢)的結(jié)果為 T上已知的公共屬性名的聯(lián)合胆剧。
keyof 的一個特性: keyof T的類型會被認(rèn)為是 string、number醉冤、symbol 的子類型秩霍。
interface Point {
x: number;
y: number;
}
type Axis = keyof Point;
// 等同于 type Axis = "x" | "y"
function cal(a: Point, b: Point, axis: Axis): number {
return (a[axis] + b[axis]) / 2;
}
cal({x:20,y:99},{x:100,y:200},'x')
type類型別名
1.可以創(chuàng)建聯(lián)合類型、元組類型蚁阳、基本類型(string,number,symbol)
//聯(lián)合類型
type Pets = 'hi' | 'age' | 'hello';
interface Dog {
x:string
}
interface Cat {
y:number
}
type Pet = Dog | Cat
//元組+泛型
//與 聲明數(shù)組類型 類似铃绒,只不過在 數(shù)組 基礎(chǔ)上更加細(xì)分化每個元素的類型。
type Pair<T> = [T, T];
const ff: Pair<number> = [1, 2];
const cc: Pair<number> = [1, 1];
const dd: Pair<string> = ['1', '2'];
2.可以利用type和映射類型快速創(chuàng)建類型
{ [ K in P ] : T }
實(shí)例
type Coord = {
[K in 'x' | 'y']: number;
};
// 得到
// type Coord = {
// x: number;
// y: number;
// }
它執(zhí)行了一個循環(huán)(可以理解為類似 for...in 的效果)螺捐,這里的 P 直接設(shè)置為 'x' | 'y' 的一個聯(lián)合類型颠悬,而 K 是一個標(biāo)識符矮燎,它映射為 P 的每一個子類型。T 為數(shù)據(jù)類型赔癌,我們直接固定為 number诞外,也可以是任何其他復(fù)雜類型。
//約束key,value為同樣的值灾票;
type Coord = { [K in 'x' | 'y']: K };
// 得到 type Coord = { x: 'x'; y: 'y'; }
3:生成類型的函數(shù)類型
可以封裝一個快速生成接口類型的函數(shù)類型:
type Unite = 'dog' | 'cat' | 'pig';
type PetInfo = {
name: string;
age: number;
};
type Coord4 = {
[K in Unite]: PetInfo;
};
const animalInfo: Coord4 = {
dog: { name: 'dogname', age: 3 },
cat: { name: 'catname', age: 3 },
pig: { name: 'pigname', age: 3 },
};
//等同于
type Creat<K extends keyof any, U> = {
[P in keyof K]: U;
};
//預(yù)置的高級類型 Record<K extends keyof any, T> 峡谊,可以直接使用
type Pets = Creat<Unite,PetInfo>
const animalInfo2: Pets = {
dog: { name: 'dogname2', age: 3 },
cat: { name: 'catname2', age: 3 },
pig: { name: 'pigname2', age: 3 },
};
interface 與 type
相同點(diǎn)
/*都可以描述一個對象或者函數(shù)*/
interface User {
name: string
age: number
}
interface SetUser {
(name: string, age: number): void;
}
type User = {
name: string
age: number
};
type SetUser = (name: string, age: number)=> void;
*都允許拓展(extends)*/
interface Name {
name: string;
}
interface User extends Name {
age: number;
}
type Name = {
name: string;
}
type User = Name & { age: number };
//interface extends type
type Name = {
name: string;
}
interface User extends Name {
age: number;
}
//type extends interface
interface Name {
name: string;
}
type User = Name & {
age: number;
}
不同點(diǎn)
type 可以聲明基本類型別名,聯(lián)合類型刊苍,元組等類型
nterface 能夠聲明合并
interface User {
name: string
age: number
}
interface User {
sex: string
}
/*
User 接口為 {
name: string
age: number
sex: string
}
*/
不清楚什么時候用interface/type既们,能用 interface 實(shí)現(xiàn),就用 interface , 如果不能就用 type 正什。
Partial
Partial 將傳入的所有屬性變?yōu)榭蛇x
// 映射類型進(jìn)行推斷
type Partial<T> = {
[P in keyof T]?: T[P];
};
interface Article {
articleId: string;
title: string;
content: string;
status: number;
}
//等同于
// interface Article1 {
// articleId?: string;
// title?: string;
// content?: string;
// status?: number;
// }
const Index = (props: Partial<Article>) => {
//to do..........
};
Required(用處不大)
將傳入的所有屬性變?yōu)楸剡x項(xiàng)贤壁,這個和 Partial 相反
type Required<T> = { [P in keyof T]-?: T[P] };
interface Article {
articleId: string;
title: string;
content: string;
status: number;
}
const Index = (props: Required<Article>) => {
//to do..........
};
Exclude
Exclude<T, U> -- 從T中剔除可以賦值給U的類型,起到過濾的作用
//官方例子
type T00 = Exclude<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d"
需求:工作日時間可調(diào)整。
type Exclude<T, U> = T extends U ? never : T;
//平常日剔除休息日就是工作日
// 一周(平常日)
type Weekday = 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday' | 'Saturday' | 'Sunday';
// 休息日
type DayOff = 'Saturday' | 'Sunday'|'Monday';
// 工作日
type WorkDay = Exclude<Weekday, DayOff>;
const day: WorkDay = 'Tuesday';
TypeScript 的映射類型
簡單語法
{ [ K in P ] : T }
type Coord = {
[K in 'x' | 'y']: T;
};
// 得到
// type Coord = {
// x: T;
// y: T;
// }
首選確定它執(zhí)行了一個循環(huán)(可以理解為類似 for...in 的效果)埠忘,這里的 P 直接設(shè)置為 'x' | 'y' 的一個聯(lián)合類型脾拆,而 K 是一個標(biāo)識符,它映射為 P 的每一個子類型莹妒。T 為數(shù)據(jù)類型名船,我們直接固定為 number,也可以是任何其他復(fù)雜類型旨怠。
因?yàn)?T 值數(shù)據(jù)類型可以是任何值渠驼,甚至數(shù)值 1 也可以,因此我們把數(shù)據(jù)類設(shè)成 K 自身也行:
type Coord = { [K in 'x' | 'y']: K };
// 得到
type Coord = { x: 'x'; y: 'y'; }
立用映射類型+keyOf關(guān)鍵字 封裝一個快速生成接口類型的函數(shù)類型Record
//封裝一個快速生成接口類型的函數(shù)類型
type Record<K extends keyof any, T> = {
[P in K]: T;
};
//K extends keyof any
等價于
//type K = 'dog' | 'cat' | 'fish'鉴腻;
type PetType = 'dog' | 'cat' | 'fish';
interface PetInfo {
name: string;
age: number;
}
type Pets = Record<PetType, PetInfo>;
const pets: Pets = {
dog: { name: 'didi', age: 1 },
cat: { name: 'cici', age: 2 },
fish: { name: 'fifi', age: 3 }
};
or
interface Pets {
dog: PetInfo;
cat: PetInfo;
fish: PetInfo;
}
額外的屬性檢查
需求:代碼遷移復(fù)用迷扇,希望原先的 js 代碼能夠遷移到 ts 中,增加類型推斷
1.使用 as 關(guān)鍵字爽哎,斷言類型蜓席,
as 語法,大部分其他場景應(yīng)該避免使用课锌,類型斷言純粹是編譯時語法厨内。類型推斷應(yīng)該盡量使用 interface / type / 基礎(chǔ)類型
//const asFoo = {};//報(bào)錯寫法
//const asFoo = {} as Foo;
const asFoo: { [propName: string]: any } = {};//推薦字符串索引用法
asFoo.bar = 2;//error類型“{}”上不存在屬性“bar”。
asFoo.title = 'as 類型斷言';//error類型“{}”上不存在屬性“bas”渺贤。
interface Foo {
bar: number;
title: string;
[propName: string]: any;//可解決報(bào)錯
}
類型保護(hù)
聯(lián)合類型時雏胃,會遇到這種問題。無法準(zhǔn)確知道是否存在某個屬性志鞍。
類型注解&類型推段
TS能夠自動的分析變量類型時瞭亮,就什么都不需要做了
TS無法分析出變量類型時,就需要使用類型注解固棚。
定義基礎(chǔ)類型可不用寫類型注解
//let count:number = 1;
let count = 1;//不需要寫類型注解统翩;
const fistCount = 1;
const secondCount = 2;
const total = fistCount + secondCount;//不需要加類型注解仙蚜,ts可直接推斷出total為number類型
//返回值類型不寫也不會報(bào)錯,但是實(shí)戰(zhàn)中一般還是要做一層約束唆缴。
function getTotal(fistCount:number,secondCount:number):number{
return fistCount + secondCount;
}
const total = getTotal(1,2);//不需要加類型注解,ts分析出是number類型