typeScript学习心得一

TypeScript的核心原则之一是对值所具有的结构进行类型检查

泛型

泛型是指一个表示类型的变量,一般用T表示,用它来代替某个实际的类型,而后通过实际调用时传入的类型来对其进行替换,可以利用泛型来适应不同类型。
TypeScript 中不建议使用 any 类型,不能保证类型安全,调试时缺乏完整的信息。
TypeScript可以使用泛型来创建可重用的组件。支持当前数据类型,同时也能支持未来的数据类型。扩展灵活。可以在编译时发现你的类型错误,从而保证类型安全。
1:泛型函数

<泛型变量名称>(参数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;
  };

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 一个接口来实现泛型约束,写法如:

<泛型变量 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: '西湖区湖底公园1号',
    },
    {
      key: '2',
      name: '吴彦祖',
      age: 42,
      address: '西湖区湖底公园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>
  );
};

keyof 关键字

keyof 关键字非常实用,后面可以看到很多工具泛型都是使用 keyof 实现的。
keyof T(索引类型查询)的结果为 T上已知的公共属性名的联合。
keyof 的一个特性: keyof T的类型会被认为是 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.可以创建联合类型、元组类型、基本类型(string,number,symbol)

  //联合类型
   type Pets = 'hi' | 'age' | 'hello';
  interface Dog {
    x:string
  }
  interface Cat {
    y:number
  }
  type Pet = Dog | Cat
  //元组+泛型
  //与 声明数组类型 类似,只不过在 数组 基础上更加细分化每个元素的类型。
  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和映射类型快速创建类型

 { [ K in P ] : T }

实例

type Coord = {
    [K in 'x' | 'y']: number;
};
// 得到
// type Coord = {
//  x: number;
//  y: number;
// }
它执行了一个循环(可以理解为类似 for...in 的效果),这里的 P 直接设置为 'x' | 'y' 的一个联合类型,而 K 是一个标识符,它映射为 P 的每一个子类型。T 为数据类型,我们直接固定为 number,也可以是任何其他复杂类型。

//约束key,value为同样的值;
type Coord = { [K in 'x' | 'y']: K };
// 得到 type Coord = { x: 'x'; y: 'y'; }

3:生成类型的函数类型
可以封装一个快速生成接口类型的函数类型:

  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;
  };
//预置的高级类型 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

相同点
/*都可以描述一个对象或者函数*/
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; 
}
不同点

type 可以声明基本类型别名,联合类型,元组等类型
nterface 能够声明合并

interface User {
  name: string
  age: number
}

interface User {
  sex: string
}
/*
User 接口为 {
  name: string
  age: number
  sex: string 
}
*/

不清楚什么时候用interface/type,能用 interface 实现,就用 interface , 如果不能就用 type 。

Partial

Partial 将传入的所有属性变为可选

// 映射类型进行推断
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(用处不大)

将传入的所有属性变为必选项,这个和 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"
需求:工作日时间可调整。
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;
// }
首选确定它执行了一个循环(可以理解为类似 for...in 的效果),这里的 P 直接设置为 'x' | 'y' 的一个联合类型,而 K 是一个标识符,它映射为 P 的每一个子类型。T 为数据类型,我们直接固定为 number,也可以是任何其他复杂类型。
因为 T 值数据类型可以是任何值,甚至数值 1 也可以,因此我们把数据类设成 K 自身也行:

type Coord = { [K in 'x' | 'y']: K };
// 得到 
type Coord = { x: 'x'; y: 'y'; }

立用映射类型+keyOf关键字 封装一个快速生成接口类型的函数类型Record

//封装一个快速生成接口类型的函数类型
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;
}

额外的属性检查

需求:代码迁移复用,希望原先的 js 代码能够迁移到 ts 中,增加类型推断

1.使用 as 关键字,断言类型,

as 语法,大部分其他场景应该避免使用,类型断言纯粹是编译时语法。类型推断应该尽量使用 interface / type / 基础类型

//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

类型保护

联合类型时,会遇到这种问题。无法准确知道是否存在某个属性。


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

TS能够自动的分析变量类型时,就什么都不需要做了
TS无法分析出变量类型时,就需要使用类型注解。
定义基础类型可不用写类型注解


image.png
//let count:number = 1;
let count = 1;//不需要写类型注解;
const fistCount = 1;
const secondCount = 2;
const total = fistCount + secondCount;//不需要加类型注解,ts可直接推断出total为number类型

//返回值类型不写也不会报错,但是实战中一般还是要做一层约束。
function getTotal(fistCount:number,secondCount:number):number{
  return fistCount + secondCount;
}
const total = getTotal(1,2);//不需要加类型注解,ts分析出是number类型
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容