• typescript中interface和type学习


    interface

    interface 表示的是接口类型,相当于定义一个对象有哪些属性;
    ?:表示可选属性;
    [k: ]: any;表示其他未知属性;

    	interface Person {
    	  name: string;
    	  age:number;
    	  fn?: (...args: any[]) => void;
    	  [k: string]: any;
    	}
    	const person: Person = {
    	  name: '张三',
    	  age: 10,
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    接口可以extends继承自另一个interface 接口 或者是接口类型的type

    	interface Name {
    	  name: string;
    	}
    	
    	interface Person extends Name {
    	  age: number;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    接口可以多次重复定义,最终合并效果同上

    	interface Person {
    	  name: string;
    	}
    	
    	interface Person {
    	  age: number;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    下面这种写法为什么会报错?

    	interface Props {
    	  [key: string]: string;
    	}
    	
    	interface dataType {
    	  title: string;
    	}
    	
    	const data: dataType = {
    	  title: '',
    	};
    	
    	const props: Props = data;
    
    	//不能将类型“dataType”分配给类型“Props”。
    	//  类型“dataType”中缺少类型“string”的索引签名。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    看似dataTypeProps的子集,实际dataType可以多次定义

    	interface Props {
    	  [key: string]: string;
    	}
    	
    	interface dataType {
    	  name: string;
    	}
    	
    	const data: dataType = {
    	  name: 'zzz',
    	};
    	
    	const props: Props = data;
    	
    	interface dataType {
    	  age: number;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    这样一看就知道是不能把dataType赋值给 Props的,这种时候就要用type去定义。

    type

    type 定义一个类型,可以是接口类型,也可以是基本类型包括:numberstringnullunderfinedboolean
    或者是模板类型'hello'`hello ${sting}`等等;

    	type Person = {
    	  name: string;
    	  age:number;
    	  fn?: (...args: any[]) => void;
    	  [k: string]: any;
    	}
    	type N = number;
    	type S = 'a' | 'b';
    	type P = Person;
    	type T = `hello ${N}`;
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    泛型

    泛型表示通过传入的类型确定最终的类型,用于支持多个类型数据;

    	function identity<T>(arg: T): T {
    	    return arg;
    	}
    
    • 1
    • 2
    • 3

    当你不想通过any丢失信息,同时又具体用到了某些属性时,
    可以通过extends泛型约束

    	function arean<T extends { width: number; height: number }>(arg: T): number {
    	  return arg.width * arg.height;
    	}
    
    • 1
    • 2
    • 3

    交叉类型 &

    T & R 表示 既是 T 又是 R

    	interface Name {
    	  name: string;
    	}
    	
    	interface Age {
    	  age: number;
    	}
    	
    	type Person = Name & Age;
    
    	
    	const personOne: Person = {
    	  name: '张三',
    	  age: 22,
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    &的作用是合并两个类型,一般情况下与接口extends作用差不多,
    但是&不会做定义类型时的前置检查,例如:

    	type A = {
    	  a: string;
    	  c: number;
    	};
    	
    	type B = {
    	  b: string;
    	  c: string;
    	};
    	
    	type C = A & B;
    	
    	//不能将类型“string”分配给类型“never”。
    	const c1: C = {
    	  a: '',
    	  b: '',
    	  c: '',
    	};
    	//不能将类型“number”分配给类型“never”。
    	const c2: C = {
    	  a: '',
    	  b: '',
    	  c: 1,
    	};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    上述例子应AB类型合并时c属性是即是number又是string,最终的结果:

    	type C = {
          a: string;
    	  b: string;
    	  c: never;
    	};
    
    • 1
    • 2
    • 3
    • 4
    • 5

    也有可能结果为never;取决于never的位置;
    这种object类型的&生成的结果更像是并集;但是并不能把&看成并集

    	type A = 'a'|'c'|'d';
    	
    	type B = 'b'|'c'|'d';
    	
    	type C = A & B; // ’c'|'d'
    
    • 1
    • 2
    • 3
    • 4
    • 5

    上面这个例子就是一个交集的效果;

    无论赋什么值都会报错。
    而当我们用extends时,会在定义时直接报错提醒:

    	type A = {
    	  a: string;
    	  c: number;
    	};
    	
    	//不能将类型“string”分配给类型“number”。
    	interface C extends A {
    	  b: string;
    	  c: string;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果一个值是交叉类型,(有可能获取的是交集也可能是并集)。

    联合类型丨

    联合类型表示一个值可以是几种类型之一。 我们用竖线(|)分隔每个类型,所以 number | string | boolean表示一个值可以是 numberstring,或 boolean

    如果一个值是联合类型,我们只能访问此联合类型的所有类型里共有的成员。

    官方提供的常用类型工具:

    	// 使所有T的属性可选
    	type Partial<T> = {
    	    [P in keyof T]?: T[P];
    	};
    	
    	// 使所有T的属性必选
    	type Required<T> = {
    	    [P in keyof T]-?: T[P];
    	};
    	
    	// 使所有T的属性只读
    	type Readonly<T> = {
    	    readonly [P in keyof T]: T[P];
    	};
    	
    	 // 从T中挑选在联合类型K的中属性
    	type Pick<T, K extends keyof T> = {
    	    [P in K]: T[P];
    	};
    	
    	 // 构造一个key在K中,值为T的类型
    	type Record<K extends keyof any, T> = {
    	    [P in K]: T;
    	};
    	
    	 // 从T类型中排除U类型
    	type Exclude<T, U> = T extends U ? never : T;
    	
    	 // 从T类型中提取U共有类型
    	type Extract<T, U> = T extends U ? T : never;
    	
    	// 从T中忽略K中的key
    	type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
    	
    	// 从T中忽略null和underfined
    	type NonNullable<T> = T & {};
    	
    	// 推断一个函数参数的类型
    	type Parameters<T extends (...args: any) => any> = 
    	T extends (...args: infer P) => any ? P : never;
    	
    	// 推断一个构造函数参数的类型
    	type ConstructorParameters<T extends abstract new (...args: any) => any> = 
    	T extends abstract new (...args: infer P) => any ? P : never;
    	
    	// 推断一个函数返回值的类型
    	type ReturnType<T extends (...args: any) => any> = 
    	T extends (...args: any) => infer R ? R : any;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    类型推断

    当使用联合类型或其他时,我们时常会遇到这种情况:

    	interface Rect {
    	  width: number;
    	  height: number;
    	  name: string;
    	}
    	interface Circular {
    	  radius: number;
    	  name: string;
    	}
    	
    	function arean(arg: Rect | Circular) {
    	  if (arg.name === 'Rect') {
    	    return (arg as Rect).width * (arg as Rect).height;
    	  }
    	  if (arg.name === 'Circular') {
    	    return Math.pow((arg as Circular).radius, 2) * Math.PI;
    	  }
    	  return 0;
    	}
    	
    	arean({ name: 'Rect', width: 10, height: 10 });
    	arean({ name: 'Circular', radius: 10 });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    单纯就这个例子可以改进:

    	interface Rect {
    	  width: number;
    	  height: number;
    	  name: 'Rect';
    	}
    	interface Circular {
    	  radius: number;
    	  name: 'Circular';
    	}
    	
    	function arean(arg: Rect | Circular) {
    	  if (arg.name === 'Rect') {
    	    return arg.width * arg.height;
    	  }
    	  if (arg.name === 'Circular') {
    	    return Math.pow(arg.radius, 2) * Math.PI;
    	  }
    	  return 0;
    	}
    	
    	arean({ name: 'Rect', width: 10, height: 10 });
    	arean({ name: 'Circular', radius: 10 });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    typescript会自动做类型推断,有时候我们不需要去自己写类型:

    	let a = 1; // a:number
    	a = ''; // 不能将类型“string”分配给类型“number”
    	
    	const B = 1; //  B: 1
    	
    	const C = {
    	  a: 1,
    	  b: 'b',
    	  c: true,
    	}; // C: {  a: number;  b: string;  c: boolean;}
    	C.b = 2; // 不能将类型“number”分配给类型“string”。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    	const A = {
    	  a: 'a',
    	  b: 'b',
    	  /** 这是c属性 */
    	  c: 'c',
    	};
    	A.c = 'aa'; // 提示:这是c属性
    	A.d = ''; //类型“{ a: string; b: string; c: string; }”上不存在属性“d”。
    	
    	const B: { [key: string]: string } = {
    	  a: 'a',
    	  b: 'b',
    	  c: 'c',
    	};
    	
    	B.d = '';
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    上面例子A推导出的类型是一个映射,vscode会有属性提示;而B是一个{ [key: string]: string }是没有固定属性的 所以没有提示 。

    通过/** 注释 */ 注释的,在引用时vscode会显示注释

    官方推荐用interface,其他无法满足需求的情况下用type。实际应用中,定义接口用interface,通过现有interface的衍生使用type

    补充Type

    	// T类型在联合类型Keys中必选其一
    	export type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Pick<
    	  T,
    	  Exclude<keyof T, Keys>
    	> &
    	  {
    	    [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>;
    	  }[Keys];
    	  
    	interface A {
    	  a: string;
    	  b: boolean;
    	  c: number;
    	}
    	
    	const a: RequireAtLeastOne<A> = {
    	  a: '',
    	};
    	
    	const b: RequireAtLeastOne<A, 'a' | 'b'> = {
    	  a: '',
    	  c: 1,
    	};
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    	// 获取T和R中的共有属性 
    	export type ExtractCommon<T extends object, R extends object> = {
    	  [K in NotNeverCommonKey<T, R>]: T[K];
    	};
    	
    	type NotNeverCommonKey<T, R> = {
    	  [K in keyof T & keyof R]: T[K] & R[K] extends never ? never : K;
    	}[keyof T & keyof R];
    	
    	// test
    	type A = {
    	  a: string;
    	  c: number;
    	  d: string;
    	};
    	
    	type B = {
    	  b: boolean;
    	  c: string;
    	  d: string;
    	};
    	
    	type C = ExtractCommon<A, B>; // { d: string; }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    ps: 不当之处,欢迎指正。

  • 相关阅读:
    爬虫 — Js 逆向
    会当“零”绝顶!天翼云零信任产品利刃出鞘
    Vue3+Elementplus引入面包屑功能
    【JavaEE网络】深入理解Socket套接字及其在网络编程中的应用
    YOLOv7改进:新颖的上下文解耦头TSCODE,即插即用,各个数据集下实现暴力涨点
    【进阶版】机器学习之支持向量机细节回顾及原理完善(09)
    C#学习记录——线程的简介及基本操作
    基于Java毕业设计休闲网络宾馆管理源码+系统+mysql+lw文档+部署软件
    求求,别在sql里格式化数据了
    Python合并拼接图片
  • 原文地址:https://blog.csdn.net/qq1036548849/article/details/127404322