TypeScript中泛型的使用詳細講解
一、泛型程序設計是一種編程風格或編程范式
二、案例:傳入的參數類型與返回的類型一樣
function identify<T>(arg: T): T {// 當前的T沒有任何約束 它可以是任何類型
return arg;
}
const foo = identify('foo'); // foo的類型是'foo'
const bar = identify('true'); // bar的類型是true三、形式類型參數
1、形式類型參數T的默認類型為boolean類型
<T = boolean>
2、必選類型參數、可選類型參數
(1)、必選類型參數:形式類型參數沒有給默認類型 , 例如: <T>
(2)、可選類型參數:形式類型參數給默認類型 , 例如: <T = boolean>
(3)、形式類型參數列表中,必選類型參數不允許出現(xiàn)在可選類型參數之后
<T = boolean, U> // 錯誤
<T, U = boolean> // 正確
四、泛型約束
在形式類型參數上允許定義一個約束條件,它能夠限定類型參數的實際類型的最大范圍。我們將類型參數的約束條件稱為泛型約束
interface point {
x: number,
y: string
}
function getPoint<T extends point>(args: T): T {
return args
}
console.log(getPoint({x: 123, y: 456})); // 錯誤
console.log(getPoint({x: 123, y: '456'})); // 正確
console.log(getPoint({x: 123, y: '456', z: 678})); // 正確
//參數的前倆個必須有并且類型必須正確 否則錯誤可以同時定義泛型約束和默認類型
<T extends number = 0 | 1>
泛型約束 ==> 類型參數
<T, U extends T> <T extends U, U>
形式類型參數不允許直接或間接地將其自身作為約束類型
<T extends T> // 錯誤 <T extends U, U extends T> // 錯誤
類型參數T沒有聲明泛型約束,那么類型參數T的基約束為空對象類型字面量“{}”。除了undefined類型和null類型外,其他任何類型都可以賦值給空對象類型字面量
<T> // 類型參數T的基數約為“{}”類型五、泛型函數
1.簡介:若一個函數的函數簽名(形參)中帶有類型參數,那么它是一個泛型函數
2.f1函數兩個參數的類型相同,函數返回值類型是數組,數組元素類型 == 參數類型。
function f1<T>(x: T, y: T): T[] {
return [x, y]
}
const a = f1(123, 456)
const b = f1('123', '456')3.f2函數兩個參數的類型不同,返回值類型為對象類型。返回值對象類型中x屬性的類型與參數x類型相同,y屬性的類型與參數y類型相同
function f2<T, U>(x: T, y: U): { x: T, y: U} {
return { x, y }
}
const a = f2('123', 456)
const b = f2(123, '456')4.f3函數接受兩個參數,參數a為任意類型的數組;參數f是一個函數,該函數的參數類型與參數a的類型相同,并返回任意類型。f3函數的返回值類型為參數f返回值類型的數組。
(這個代碼的粘貼的 我也懵逼)
function f3<T, U>(a: T[], f: (x: T) => U): U[] {
return a.map(f);
}
// f3<number, boolean> 約束T為number類型 U為boolean類型
const a: boolean[] = f3<number, boolean>([1, 2, 3], n => !! n)六、泛型函數類型推斷
function f0<T>(x: T): T {
return x
}
const a = f0(123) // 推斷出類型為 123
const b = f0('123') // 推斷出類型為 '123'此例中編譯器推斷出的不是number 和 string類型,而是字符串字面量類型123和“123”。因為TS原則,始終將字面量視為字面量類型,只在必要的時候才會將字面量類型放寬為某種基礎類型,例如string類型。此例中,字符串字面量類型“123”是比string類型更加精確的類型。
類型參數只在函數簽名中出現(xiàn)一次,則說明它與其他值沒有關聯(lián),則不需要使用類型參數,直接聲明實際類型即可。
幾乎任何函數都可以聲明為泛型函數。若泛型函數的類型參數不表示參數之間或參數與返回值之間的某種關系,那么使用泛型函數可能是一種反模式。
// 沒必要使用泛型
function f<T>(x: T): void {
console.log(x)
}
// 直接限定就好了
function f(x: number): void {
console.log(x)
}補充:應用場景
通過上面初步的了解,后述在編寫 typescript 的時候,定義函數,接口或者類的時候,不預先定義好具體的類型,而在使用的時候在指定類型的一種特性的時候,這種情況下就可以使用泛型
靈活的使用泛型定義類型,是掌握typescript 必經之路
<泛型變量名稱>(參數1: 泛型變量, 參數2: 泛型變量, ...參數n: 泛型變量) => 泛型變量
/*------------基礎使用方法------------*/
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']);
/* -----------泛型箭頭函數-------------*/
const identity = <T,>(arg: T): T => {
return arg;
};
const identity2: <T>(arg: T) => T = (arg) => {
return arg;
};
泛型接口
/* -------------泛型接口-------------*/
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',
},
];
泛型類
/*--------------泛型類---------------*/
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 一個接口來實現(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) // 報錯
logIndex<number[]>(arr) // 允許
logIndex(arr) // 自動類型推導,允許
泛型應用場景之一
/*-------------應用場景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>泛型應用場景</h3>
<MyTable dataSource={dataSource} columns={columns} />
</div>
);
};
總結
到此這篇關于TypeScript中泛型使用的文章就介紹到這了,更多相關TypeScript泛型的使用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
mockjs,json-server一起搭建前端通用的數據模擬框架教程
下面小編就為大家分享一篇mockjs,json-server一起搭建前端通用的數據模擬框架教程,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12

