typeScript學(xué)習(xí)心得一

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ò)展靈活??梢栽诰幾g時發(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) // 報錯
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 相反


image.png
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 = {};//報錯寫法
//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;//可解決報錯
}
image.png

類型保護(hù)

聯(lián)合類型時,會遇到這種問題。無法準(zhǔn)確知道是否存在某個屬性。


image.png
類型注解&類型推段

TS能夠自動的分析變量類型時,就什么都不需要做了
TS無法分析出變量類型時,就需要使用類型注解。
定義基礎(chǔ)類型可不用寫類型注解


image.png
//let count:number = 1;
let count = 1;//不需要寫類型注解;
const fistCount = 1;
const secondCount = 2;
const total = fistCount + secondCount;//不需要加類型注解,ts可直接推斷出total為number類型

//返回值類型不寫也不會報錯,但是實(shí)戰(zhàn)中一般還是要做一層約束。
function getTotal(fistCount:number,secondCount:number):number{
  return fistCount + secondCount;
}
const total = getTotal(1,2);//不需要加類型注解,ts分析出是number類型
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容