TypeScript使用

215 阅读17分钟

TypeScript概要

JavaScrip编译与运行的流程大致如下:

第一步:把程序解析为AST(去掉空白、注释、制表符、空格等) 第二步:把AST编译成字符码 第三步:运行时计算字节码

TypeScript编译与运行的流程大致如下:

第一步:把TypeScript源码解析为AST 第二步:类型检查器检查AST 第三步:把TypeScript AST解析为JavaScript源码 第四步:把JavaScript源码解析为JavaScript AST 第五步:把AST编译成字节码 第六步:运行时计算字节码

TypeScript中的类型对程序输出没有任何影响,类型只在类型检查这一步使用

TypeScript是以JavaScript为基础构建的语言,也称为JavaScript的超集。 TypeScript扩展了JavaScript,并添加了类型。 TypeScript可以在任何支持JavaScript的平台中运行,由于无法直接执行,需要使用插件编译为JavaScript。

TypeScript基础

类型操作

1. 类型系统

TypeScript类型系统分为以下两种:

  • 通过显式句法告诉编译器所有值的类型
  • 自动推导值的类型

最好让TypeScript推导类型,少数情况下才显式注解类型

类型系统特性JavaScriptTypeScript
类型是如何绑定的?动态静态
是否自动转换类型?否(多数情况下)
何时检查类型?运行时编译时
何时报告错误?运行时(多数情况下)编译时(多数情况下)

2. 类型全解

类型举例描述
number1、2、-10任意数字
string'hellow'、'123'任意字符串
booleantrue、false布尔值
字面量其本身限制变量的值即为字面量的值
any*任意类型
unknown*类型安全的any
Functionfunction fn(f:Function){ return f(1,2,3); }函数类型,可以调用bind、call等API
void空值(undefined)无值或undefined
never无值不能是任何值
object{name:'小明',age:25}任意的JS对象
array[1,2,3]任意的JS数组
tuple[4,5]元素类型可以不同,TS新增类型,固定长度的数组
enumenum{A,B}枚举,TS新增类型

1)字面量:仅表示一个值的类型

let b: "male" | "female"; // 只能是male或者female
b = "male";
b = "female";

字面量类型支持模版拼接

type Direction = 'left' | 'right' | 'top' | 'bottom';
type marginDirection = `margin-${Direction}`;
type paddinngDirection = `padding-${Direction}`;

2)any:表示的是任意类型(类似类型教父),一个变量设置类型any 后相当于对该变量关闭了TS 的类型检测,any类型可以赋值给任意类型变量

let d: any;
let d;

3)unknown:表示未知类型,不能赋值给其他类型变量,当无法预知一个值的类型时使用。

注意⚠️:TypeScript不会把任何值推导为unknown类型,必须显式注解;unknown类型的值可以进行比较;不能假定unknown类型的值为某一特定类型,必须先向TypeScript证明一个值明确是某个类型

let d: unknown

4)void:表示无返回值

function fn():void{}

5)never:表示永远不会返回结果,包括不会返回undefined

function fn():never{
    throw new Error('程序运行错误');
}

function fn():never{
   while(true){
      doSomething();
   }
}

6)tuple:固定长度,各索引位上的值具有固定的已知类型

注意⚠️:元组支持可选元素和剩余元素

let t: [string, number, object, boolean] = ['h',1,{},true];
let t: [string, number, object, boolean?] = ['h',1,{}];
let t: [string, ...string[]] = ['h','e'];

7)enum:列举类型中包含的各个值,是一种无序的数据结构,把键映射到值上。

枚举分为两类:字符串到字符串之间的映射、字符串到数字之间的映射。

TypeScript可以自动为枚举中的各个成员推导对应的数字,也可以手动设置。

enum Gender {
   Male = 0,
   Female = 1
}

注意⚠️:一个枚举可以分为多次声明,TypeScript可以自动把各个部分合并在一起,但是却只能推导出其中一部分的值

3. 索引签名

[key: T]: U

索引签名的意思是“在这个对象中,类型为T的键对应的值为U类型”。

键的类型(T)必须可赋值给number或string或symbol

适用场景:显示声明键的类型、添加更多的键

class MyClass {
   // 属性名是字符串类型,属性值可以使布尔值,也可以是函数
   [s: string]: boolean | ((s: string) => boolean);
   // 参数为字符串类型,返回值
   check(s: string) { 
      return this[s] as boolean;
   }
}

// 使用
class MyClass {
   x = true;
}

键的类型不能是字面量类型或泛型类型

type D = {
    [K:'id']: string; // error
}

image.png

4. 类型声明

类型声明是TS非常重要的一个特点,通过类型声明可以指定TS中变量 (参数、形参) 的类型。

指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明。如果符合则赋值,否则报错。

let 变量: 类型;

let 变量: 类型 = 值;

function fn(参数: 类型,参数: 类型): 类型{... ...}

TS拥有自动的类型判断机制,当对变量的声明和赋值同时进行时,TS编译器会自动判断变量的类型。

let a:number = 10;
a = '10'; // ts:不能将类型“string”分配给类型“number”

5. 类型别名

作用:为类型声明一个别名

type Point = { x:number, y:string };
type IDType = number | string;

// 使用别名
function fn(id:IDType):void{};

扩展类型:&

// 扩展
type Animal = { name: string };
type Bear = Animal & { honey: boolean };

// 使用
const bear:Bear = { name: 'winnie', honey: true }

不允许添加字段:

type Animal = {
  name: string;
}

type Animal = { // ts Error:标识符“Animal”重复。
  age: number;
}

注意⚠️:

type声明类型时,不能通过对同一标识符重复声明的方式添加类型;

TypeScript无法推导类型别名,因此必须显式注解;

类型别名采用块级作用域,内部的类型别名将遮盖外部的类型别名;

内置映射类型Pick、Partial、Record、Required等都是以type定义的

image.png

6. 联合类型

声明变量为一个或者多个其他类型组成的集合

let b: string | number // b可以是字符串类型或者数值型

适用场景:某个变量或者参数的类型不确定,可以是多个类型时使用。

function welcomePeople(x: string[] | string){
   if (Array.isArray(x)) {
      console.log('Hello, ' + x.join('and'));
   }else{
      console.log( 'Welcome lone traveler' + x);
   }
}

注意⚠️:如果需要使用某个特定类型的原生API时,需要对类型进行判断,否则会抛出错误。类型判断的方法包括JS中的typeof、toString、instanceOf、Array.isArray等。

7. 类型断言

某些情况下TS编译对于变量的类型不确定,此时可以通过类型断言来告诉编译器变量的类型

第一种形式:value as 类型

let somevalue: unknown = "this is a string";
let strLength: number = (somevalue as string).length;

第二种形式: <类型>value

let somevalue: unknown = "this is a string";
let strLength: number = (<string> somevalue).length;

8. 接口

作用:声明类型的一种方式,可以定义一个公共的类型供重复使用

interface Point {
   x: number;
   y: number;
}
function printCoord(pt: Point) {
   console.log ("坐标x的值是. " + pt.x);
   console.log("坐标y的值是" + pt.y);
}

printCoord({ x: 100, y: 100 });

扩展接口:extends

// extends 关键字扩展接口
interface Animal { name: string }
interface Bear extends Animal { honey: boolean }

// 使用
const bear: Bear = { name: 'winie', honey: true }

5)添加字段

// 向现有的类型添加字段
interface MyWindow { count: number };
interface MyWindow { title: string };
// 使用
const w: MyWindow = { title: 'hello', count: 100 };

6)类型别名与接口区别

第一:类型别名更为通用,可以是任何类型,包括类型表达式(类型、类型运算等);接口声明中必须是结构

第二:扩展接口时,TypeScript将检查扩展的接口是否可以赋值给被扩展的接口;重复声明同一个类型别名,TypeScript会报错

第三:同一个作用域中的多个同名接口将自动合并,类型别名则会直接报错

9. 类型守卫

1)适用场景

用于处理联合类型变量的场景,将类型范围缩小

类型防护:特殊类型的检查

类型缩小:将类型细化为比声明更具体的类型的过程

2)typeof类型守卫

typeof strs = 
   "object"
   "string"
   "number"
   "bigint"
   "boolean"
   "symbol" 
   "undefined"
   "function"

3)真值缩小

通过Boolean()方式可以将值转换为true或者false

Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false
Boolean(null) // false
Boolean(undefined) // false
Boolean(0n) // false BigInt零的表示

通过!!方式也可以将值转换为true或者false

!!0  === false
!!NaN === false
!!'' === false
!!null === false
!!undefined ===false
!!0n === false

4)in操作符缩小

'value' in x(联合类型)

返回值为true:x具有可选或者必须属性的值

返回值为false:x具有可选或者缺失属性的值

type Fish = { swim: ()=>void };
type Bird = { fly: ()=>void };
type Human = { swim?: ()=>void; fly?: ()=>void }


function move(animal: Fish | Bird | Human){
   if ("swim" in animal) { // 可能是Fish或者Human类型
      return (animal as Fish).swim(); // 需要配合使用as,进行类型断言,否则报错
   }
   return (animal as Bird).fly();
}

5)instanceof操作符缩小

作用:检查一个值是否为某个类型实例

x instanceof FOO

返回值为true:x是FOO类型实例

返回值为false:x不是FOO类型实例

function logValue(x: Date){
   if(x instanceof Date){
      console.log(x.toLocalstring())
   }else{
      console.log(x.toUpperCase())
   }
}

6)分配缩小

通过判断条件选择为某个变量赋不同的值,从而缩小变量类型范围

let x = Math random() < 0.5 ? 10 : 'hello world';

10. 类型谓词

作用:有效的根据条件缩小类型范围,和typeof、in、instanceof类似。

类型谓词采用parameterName is Type格式,其中parameterName 必须是当前函数中的参数名称。

function runner(params: null | undefined | string): void {
   if (params === null) {
    console.log('null');
   } else {
    console.log(params);
   }
}

使用类型谓词优化条件判断

function isUndef (val: any): val is null | undefined { 
    return val == null; 
}
function runner(params: null | undefined | string): void {
   if (isUndef(params)) {
    console.log('null');
   } else {
    console.log(params);
   }
}

image.png

11. 交叉类型&

A & B表示将A类型和B类型合并,如果存在重复属性时,取重复属性中范围最大的那个(any和string则为any),如果重复属性没有交集则为never(string和number)

interface A {
    name:string;
    age:number;
}

interface B {
    name:string;
    school: string;
}
type C = A & B;
// type C = {name:string;age:number;school:string;}

function函数

1. 注解this类型

程序中this的值取决于调用函数的方式,而不受声明方式的干扰。如果函数中使用this,需要在函数的第一个参数中声明this的类型。

function greet(this:Array<number>){
    return `${this.length}`;
}
greet.call([1]);
greet(); // Error

image.png

2. 调用签名

作用:表示函数类型的句法,没有函数的定义体,无法推导返回类型,必须显式注解

(a: number, b: number) => number

注意⚠️:调用签名中不再使用 =>,而是用“:”代替

type DescribableFunction = {
   description: string;
   (someArg: number): boolean
}

function doSomething(fn: DescribableFunction) {
   console.log(fn.description + 'returned' + fn(6)); // 参数为函数类型,函数包括一个属性
}

function fn1(n: number) { // 创建函数类型
   console.log(n);
   return true;
}

fn1.description = "hello"; // 为函数添加属性

doSomething(fn1);

3. 重载签名

作用:根据参数数量不同,执行不同的逻辑主体,一般包括多个重载函数和一个实现函数。

如果函数有多个重载签名,在调用方看来,函数的类型是各个签名的并集。

// 重载函数签名
function makeDate (timestamp: number): Date;
function makeDate(m: number, d: number,y: number): Date;

// 实现函数签名,接收参数为1个或3个
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
  if(d !== undefined && y !== undefined){
    return new Date(y, mOrTimestamp, d);
  }else{
    return new Date(mOrTimestamp);
  }
}

makeDate(123456);
makeDate(1,2,3);

注意⚠️:重载签名和实现签名的参数数量、参数类型、返回值类型需一致

⚠️:参数数量必须一致

function fn(x:string):void;
function fn(){}

⚠️:参数类型必须一致

function fn(x:string):void;
function fn(x:boolean):void;
function fn(x:string | boolean){};

⚠️:返回值类型必须一致

functionfn(x:string):string;
functionfn(x:boolean):boolean;

functionfn(x:string | boolean):string|boolean{
   return true || '100';
}

注意⚠️:在可能的情况下,总是倾向于使用联合类型的参数而不是重载参数

function fn(x:string):string;
function fn(x:boolean):boolean;
function fn(x:string | boolean):string|boolean{
  return '100';
}

fn(Math.random() > 0.5 ? '123' : true) // Error

// 使用联合类型代替函数重载签名
function fn(x:string | boolean):string|boolean{
  return '100';
}

fn(Math.random() > 0.5 ? '123' : true)

4. 构造签名

class Ctor {
   s: string;
   constructor(s: string) {
      this.s = s
   }
}

type SomeConstructor = {
   new (s: string): Ctor
}

function fn(ctor: SomeConstructor){
   return new ctor('hello');
}

class类

1. 类的静态属性

class Artical {
    title: string; // 必须属性
    content: string;
    data?: string; // 可选属性
    level = 3 // 属性默认值

    constructor(title:string,content:string){
        this.title = title;
        this.content = content;
    }
}
const artical1 = new Artical('国家地理', '酸酸臭臭一家亲');

2. 修饰符

  • public:默认值,不写的时候就是public,任何对象在任何地方均可以访问
  • private:私有的,只能在类中访问
  • protected:受保护的,能在当前类和子类中访问,不能在实例中访问
  • static:不需要实例化,可以直接通过类调用
class Greeter {
    public greet() {
        console.log("hi!");
    }
    private sun(){
        console.log("sun");
    }
    protected sleep(){
        console.log('sleep');
    }
    static eat(){
        console.log('eat');
    }
}
class Item extends Greeter {
    constructor(){
        super();
    }
}
Greeter.eat(); // eat
const item = new Item();
item.greet(); // hi!
item.sun(); // Error
item.sleep(); // Error

image.png

image.png

注意⚠️:静态成员也可以使用public、protected、private修饰符;静态成员也可以被继承;

修饰符可以连用,static必须在其他修饰符后面,如public static name:string

  • abstract:抽象类和属性及方法,规定子类必须具有,本身不会实例化
abstract class Animal {
    abstract name:string;
}

class Dog extends Animal {
    name = '胖胖'
}

3. super

作用:子类中可以使用super调用父类中的同名方法

适用场景:

  • 方法调用:super.take
  • 构造函数调用:super()

使用super只能访问父类中的方法,不能访问父类中的属性

4. 以this为返回类型

适用场景:以this注解返回值的类型,TypeScript会自动推导

type SetType = {
  has: (value:number) => boolean,
  add: (value:number) => this
}

5. implements

作用:指名该类满足某个接口


interface Animal {
  eat(food:string):void;
  sleep(hours:number):void;
}

// 满足单个接口
class Cat implements Animal {
  eat(food:string){
    console.log(`吃了${food}`);
  };
  
  sleep(hours: number): void {
    console.log(`睡了${hours}小时`);
  }
}

// 满足多个接口
class Cat implements Animal, Feline {}

6. 类的初始化顺序

Class Base {
   name ="base";
   constructor(){console.log("My name is " + this.name);
}

Class Derived extends Base {
   name = 'derived';
}

const derived = new Derived(); // base

基类的字段被初始化 => 基类构造函数运行 => 派生类的字段被初始化 => 派生类构造函数运行

对象

1. 声明类型

interface person {
  name:string;
  age:number
}

type person = {
  name:string;
  age:number
}

2. 属性设置

interface person {
  name:string; // 必传属性
  sex?:string // 可选属性
  readonly hony:string[] // 只读属性
}

type person = {
  name:string; // 必传属性
  sex?: string // 可选属性
} 

readonly只能限制当前属性,并不能限制属性内部的其他属性,相当于浅只读

3. 索引签名

interface StringArray {
   [index: number]: string,
   [prop: string]: string,
   readonly [index: number]: string
}
const myArray: StringArray = ['a','b'];
const seconditem = myArray[0];

4. 类型处理

1)扩展类型

interface person {
  name:string;
  age:number;
  sex?:string
  readonly hony:string[]
}

interface chinese {
  china: string;
}

// 扩展单个类型
interface Femal extends person {
  school: string
}
// 扩展多个类型
interface Femal extends person,chinese {
  school: string;
}

2)交叉类型&

type Color ={
  color:string;
}

type FontStyle = {
  size:number;
}

type ColorAndFont = Color & FontStyle;

let c:ColorAndFont = {
  color:'red',
  size:200
}

类型操作

1. keyof

keyof T获取类型 T 的所有公共属性键,会返回一个联合类型,该联合类型包含 T 类型中所有可索引的公共属性名。

interface Person {
  name: string;
  age: number;
  address?: string;
}
 
type PersonKeys = keyof Person; 
// PersonKeys的类型是"name"|"age"|"address"

2. typeof

typeof用于获取给定表达式的类型,返回一个表达式类型的字符串。

 typeof undefined // 'undefined'
 typeof null // 'object'
 typeof true // 'boolean'
 typeof 1 // 'number'
 typeof 'hello' // 'string'
 typeof BigInt(1) // 'bigint'
 typeof Symbol(1) // 'symbol'
 typeof function a(){} // 'function'

将 typeof 与条件类型结合,我们可以在运行时对不同类型的代码进行条件分支。

function test (num: number | string): number | string {
  if (typeof num === 'number') {
    return ++num;
  } else {
    return +num + 1;
  }
}

typeof也可以用于复杂类型判断。

const appconfig = {
  id: 1,
  text: 'app',
}
type appType = typeof appconfig // {id: number;text: string}
const appconfigtest: appType = {}

3. in

通过in生成映射类型,in可以理解为js中的for...in循环操作。

enum Letter {
    A=a,
    B=b,
    C=c
}
type LetterMap = {
    [key in Letter]:string
}

等价于

type _LetterMap={
    a:string
    b:string
    c:string 
}

项目中使用

type Item = {
    a:string;
    b:number;
    c:boolean;
}
type T1 = {
    [P in 'x' | 'y']:number;
}
// type T1 = {  x: number;  y: number; }

type T2 = {
    [P in 'x' | 'y']: P
}
// type T2 = {  x: "x";  y: "y"; }

type T3 = {
    [P in 'a' | 'b']: Item[P]
}
// type T3 = {  a: string;  b: number; }

type T4 = {
    [P in keyof Item]:Item[P]
}
// type T4 = {  a: string;  b: number;  c: boolean; }

泛型

1. 泛型作用

当定义一个变量不确定类型的时候有两种解决方式:

  • any:失去了TS类型保护的优势
  • 泛型:泛型指的是在定义函数/接口/类型时,不预先指定具体的类型,而是在使用的时候再指定类型限制的一种特性

2. 泛型使用

函数中使用

function test <T> (arg:T):T{
  console.log(arg);
  return arg;
}
test<number>(111);// 返回值是number类型的 111
test<string | boolean>('hahaha')//返回值是string类型的 hahaha
test<string | boolean>(true);//返回值是布尔类型的 true

接口中使用

interface Search {
  <T,Y>(name:T,age:Y):T
}
let fn:Search = function <T, Y>(name: T, id:Y):T {
  console.log(name, id)
  return name;
}
fn('li',11);//编译器会自动识别传入的参数,将传入的参数的类型认为是泛型指定的类型

类中使用

class Animal<T> {
 name:T;
 constructor(name: T){
  this.name = name;
 }
 action<T>(say:T) {
   console.log(say)
 }
}
let cat = new Animal('cat');
cat.action('mimi');

尖括号的位置限定泛型的作用域,并且在一对尖括号中可以声明任意个以逗号分隔的泛型参数

3. 泛型约束

// 单个约束
T extends U

// 多个约束
T extends U & V & W

当Type类型无法确定,但又需要参数具有某个属性时,需要对Type进行限制,从而限制了参数的类型。

function longest<Type extends {length: number}>(a: Type, b: Type){
   if (a.length >= b.length) {
      return a;
   }else{
      return b;
   }
}

const result = longest([1,2,3],[4,5]); // [1,2,3]
const longerString = longest('felix', 'lu') // 'felix'
const notok = longest(10,100) // 报错,number没有length属性

4. 泛型指定类型

由于使用泛型,TS会自动推断Type类型,当需要改变Type时,会报错。为了解决这个问题,需要使用指定函数参数的类型

function combine<T>(arr1: T[], arr2: T[]): T[] {
   return arr1.concat(arr2);
}
const arr = combine(["string"],[1,2,3]) // TS会推断Type等于string

通过<>指定多个参数类型

const arr = combine<string | number>(["string"],[1,2,3])

注意⚠️

  • 可能的情况下,使用类型参数本身,而不是对其进行约束
  • 总是尽可能少地使用类型参数
  • 如果一个类型的参数只出现在一个地方,请重新考虑你是否真的需要它

5. 泛型默认类型

type MyEvent<T = HTMLElement> = {
  target: T,
  type: string
}

注意⚠️:泛型默认类型需要放在没有默认类型的泛型之后

TypeScript进阶

extends

1. 继承

class Animal{
  move(){
    console.log("Moving along!");
  }
}
class Person extends Animal{
  talk(info){
    console.log(info)
  }
}
const person = new Person();
person.move();
person.talk('hello world')

2. 类型约束

interface ILength {
  length: number
}
function id<Type extends ILength>(value: Type): Type {
  console.log(value.length)
  return value
}

3. 接口扩展

interface Animal {
  name: string
}
interface Person extends Animal {
  level: number
}
const person: Person = {
  name: 'Perter',
  level: 1
}

4. 条件类型判断

当T类型可以赋值给U类型时,则返回X类型,否则返回Y类型。

T extends U ? X : Y
  • T U X Y 四个是占位符,分别表示四种类型;
  • T extends U表示T类型能被赋值给U类型,这里还涉及到TS类型兼容性

特殊类型兼容性判断:

  • any:any 可以赋值给除 never 以外的任何类型,任何类型都可以赋值给 any
  • never:never 可以赋值给任何类型,其他任何类型不能赋值给 never
  • unknown:unknow 只能赋值给 any 类型,其他任何类型都可以赋值给 unknown

比如工具类型 Exclude 的实现,就是基于条件类型

// 排除联合类型 `T` 中匹配的类型
type MyExclude<T, Key>  T extends Key ? never : T`

type T0 = MyExclude<"a"|"b"|"c","a">; // type T0 = "b"|"c"
type T1 = MyExclude<"a"|"b"|"c","a"|"b">; // type T1 = "c"

infer

在TypeScript中,infer是一个关键字,用于在条件类型中声明类型变量,存储在模式匹配过程中捕获的类型。

infer U 相当于引入一个新的变量U,并且可以在后续代码中捕获。

infer语句只能在extends子句中使用; infer声明的变量只能在条件分支中true时使用

1. 获取函数的返回值

目前TS已经提供了ReturnType<T>类型工具,如果传入函数类型则返回函数的返回值类型。

let r: ReturnType<() => number>

image.png

通过infer关键字也可以实现一个ReturnType<T>工具

type MyReturn<T> = T extends (...args: any[]) => infer U ? U : T
let r: MyReturn<number>

image.png

2. 获取数组元素的类型

type InferArray<T> = T extends Array<infer U> ? U : T
let r:InferArray<string>

image.png

3. 提取类型的部分属性为新类型

假设目前有一个类型,包含两个属性name和age,要求从Person类型中提取出只包含名字的子类型。

type Person = {
  name: string;
  age: number;
}

type ExtractName<T> = T extends { name: infer U; age: number } ? U : never;

type NameOnly = ExtractName<Person>;

image.png

内置条件类型

1. Exclude(排除)

Exclude<T, U>表示从T中剔除可以赋值给U的类型,如果 T 是 U 的子类型则返回 never,不是则返回 T。

type A = number | string | boolean
type B = number | boolean
type Foo = Exclude<A, B>

image.png

2. Extract(提取)

Extract<T, U>表示提取T中可以赋值给U的类型,和 Exclude 作用相反。

type A = number | string | boolean
type B = number | boolean
type Foo = Extract<A, B>

image.png

3. NonNullable

NonNullable<T>表示从T中剔除null和undefined。

// 源码
type NonNullable<T> = T extends null | undefined ? never : T;
// 使用
type t = NonNullable<'name' | undefined | null>;

image.png

4. ReturnType

ReturnType<T>表示获取函数返回值类型。

// 源码
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
// 使用
type t = ReturnType<(name: string) => string | number>

image.png

function getUser() {
  return {name: 'xxx', age: 10}
}
type GetUserType = typeof getUser; // 获取函数类型
type ReturnUser = ReturnType<GetUserType> // 获取函数返回值类型

image.png

image.png

5. InstanceType

InstanceType<T>表示获取构造函数的实例类型。

// 源码
type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;
// 使用
type t = InstanceType<new (name: string) =>{name:string,age:number}> 

image.png

内置映射类型

1. Record

Record<K, V>创建一个对象类型,其中所有属性的键都是由 K 类型表示,值都是由 V 类型表示。

type Person = {
    name:string,
    age:number,
    sex:'F' | 'M'
}
type UserMap = Record<string, Person>;

image.png

2. Partial(可选)

用于生成一个新类型,该类型与 T 拥有相同的属性,但是所有属性皆为可选项。

interface Foo {
    name: string
    age: number
}
type Bar = Partial<Foo>

image.png

// 源码
type MyPartial<T> = {
    [P in keyof T]?:T[P]
}

3. Required(必须)

用于生成一个新类型,该类型与 T 拥有相同的属性,但是所有属性皆为必选项。

interface Foo {
    name: string
    age?: number
}
type Bar = Required<Foo>

image.png

4. Readonly(只读)

用于生成一个新类型,该类型与 T 拥有相同的属性,但是所有属性皆为只读不可修改。

interface Foo {
    name: string
    age: number
}
type Bar = Readonly<Foo>

image.png

5. Pick(选择)

用于生成一个新类型,该类型包含T中部分属性,所有属性均来源于keys

interface Foo {
    name: string;
    age?: number;
    gender: string;
}
type Bar = Pick<Foo, 'age' | 'gender'>

//源码
type Pick<T,K extends keyof T> = {
    [P in K]: T[P];
}

image.png

6. Omit(省略)

用于生成一个新类型,该类型拥有 T 中除了 K 属性以外的所有属性。

type Foo = {
  name: string;
  age?: number;
  gender: string;
}
type Bar = Omit<Foo, 'age' | 'gender'>

//源码
type Omit<T,K extends keyof any>=Pick<T, Exclude<keyof T, k>>

image.png

7. Parameters

用于以元组的方式获得函数的入参类型。

type t = Parameters<(name: string) => any>;

image.png

type t2 = Parameters<((name: string) => any)  | ((age: number) => any)>;

image.png

8. ConstructorParameters

用于以元组的方式获得构造函数的入参类型。

type t = ConstructorParameters<(new (name: string) => any)|(new (age: number) => any)>;

image.png