ts 学习记录

关键字解读

extends

有三种用法。

扩展 interface 接口的属性。
interface def {
	d: number
	e: number
	f: number
}

// 扩展 abc 的类型
interface abc extends def {
	a: string
	b: string
	c: string
}
判断是否满足是后面类型的子集

比如 Pick 工具类型的实现。

K 必须满足是 T 类型的子集。

/**
 * From T, pick a set of properties whose keys are in the union K
 */
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

比如

type abc = Pick<{
	a: string
	b: string
	c: string
}, 'a' | 'b'>

const ab: abc = {
  a: '1',
  b: '12',
  // c: '111'
}
像三元运算符一样
// 如果 T 可以满足类型 Person 则返回 Person 类型,否则为 T 类型
type IsPerson<T> = T extends Person ? Person : T;

typeof

在 TS 中用于类型表达时,typeof 可以用于从一个变量上获取它的类型。

对于获取一个对象、数组的类型是很方便的。

举一个例子:

const value: number = 10;

const value2: typeof vlaue = 100;       // const value2: number

但是请注意下面这种情况:

const value = 10;

const value2: typeof vlaue = 100;       

// const value2: 10
// ERROR: Type '100' is not assignable to type '10' 

经测试,number string boolean 类型在没有声明而直接赋值的情况下,都会存在这个问题

keyof

keyof 是TS中的索引类型查询操作符。keyof T 会得到由 T 上已知的公共属性名组成的联合类型。

Keyof T, the index type query operator. For any type T, keyof T is the union of known, public property names of T

举个例子:

interface Person {
    name: string;
    age: number;
    phoneNum: number;
}

type PersonProperty = keyof Person;

// type PersonProperty = "name" | "age" | "phoneNum"

keyof 在我们限制类型或者枚举属性时还是非常常见的,比如下面这个小例子:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
    return obj[key];
}

T[K] 在TS里称作索引访问操作符(indexed access operator)。它可以为我们准确解析目标对象上的对应属性的正确类型。

在下面的介绍,我们可以继续看到 keyof 的应用。

in

in 操作符用于遍历目标类型的公开属性名。类似 for … in 的机制。

从其用途看,我们很容易想到 in 可用于联合类型或者枚举类型。

使用于枚举类型

我们可以像下面这样使用枚举类型:

enum Letter {
    A,
    B,
    C,
}

type LetterMap = {
    [key in Letter]: string;
}

// type LetterMap = {
//     0: string;
//     1: string;
//     2: string;
// }
使用于联合类型

我们可以像下面这样使用联合类型:

type Property = 'name' | 'age' | 'phoneNum';

type PropertyObject = {
    [key in Property]: string;
}

// type PropertyObject = {
//     name: string;
//     age: string;
//     phoneNum: string;
// }

利用可用于联合类型的特性,我们有下面这种很常见的做法(仅举例):

type ToString<T> {
    [key in keyof T]: string;
}
使用于基础类型

值得一提的是,一些基础类型(string, number, symbol)也可以用于 in 操作符:

type StringKey = {
    [key in string]: any;
}

// type StringKey = {
//     [x: string]: any;
// }

type NumberKey =  {
    [key in number]: any;
}

// type NumberKey = {
//     [x: number]: any;
// }

type SymbolKey = {
    [key in symbol]: any;
}

const abc: SymbolKey = {
  [Symbol(1)]: 1
}

infer

在 TS 中,如果我们在 generator 函数中使用了 yield 表达式,我们就会丢失类型。比如下面这样:

function test(num: number) {
  return 1
}


function *task() {
  const result: ReturnType<typeof test> = yield test(1)
}

在这里插入图片描述

如果去掉 infer 关键字。所以这里的 infer 就像是在最外面了一个类型变量,让表达式里能获取到该变量。
在这里插入图片描述

is

像下面这种情况,ts 能推到出正确的类型。
在这里插入图片描述
在这里插入图片描述

但是像这种情况,ts 只知道返回函数类型是 boolean,并不会再去推断 value 的类型。所以 is 在这里的作用就是:当返回值为 true 时,value 被推导为 string 类型。

function isString(value: any): value is string {
    return typeof value === 'string';
}

function isNumber(value: any): value is number {
  return typeof value === 'number'
}

function doSometing(value: any) {
    if (isString(value)) {
      // string 类型
      value.slice(0, 10)
    } else if(isNumber(value)) {
      // number 类型
      value.toFixed()
    } else {
      // any 类型
      value
    }
}

其实,TS 代码中 Array.isArray 也是使用了这样的声明!

type 和 interface 异同总结

type 和 interface 最大的两点区别就是:是否能定义基本类型、同名是否能自动合并。

1、type 能定义基本类型、联合类型等,而 interface 不可以。interface 只能定义对象类型。

2、type 要合并类型只能通过 & 符号进行合并,同名的 type 会起冲突。而 interface 可以通过 extends 合并,也可以定义同名的 interface,其属性会自动合并。

type

type 可以定义一个新的类型。比如基本类型、联合类型、交叉类型等。

type MyNumber = number;
type StringOrNumber = string | number;
type Text = string | string[];
type Point = [number, number];
type Callback = (data: string) => void;

在 ts 中,Partial、Required、Pick、Record 和 Exclude 等工具类型其实都是用 type 定义的。这些类型定义都可以在 lib.es5.d.ts 文件中找到。

Partial

/**
 * Make all properties in T optional
 */
type Partial<T> = {
    [P in keyof T]?: T[P];
};

Required

/**
 * Make all properties in T required
 */
type Required<T> = {
    [P in keyof T]-?: T[P];
};

Pick

从 T 中选择一些属性,这些属性由联合类型组成。比如 ‘name’ | ‘age’

/**
 * From T, pick a set of properties whose keys are in the union K
 */
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

Record

/**
 * Construct a type with a set of properties K of type T
 */
type Record<K extends keyof any, T> = {
    [P in K]: T;
};

Exclude

/**
 * Exclude from T those types that are assignable to U
 */
type Exclude<T, U> = T extends U ? never : T;

Extract

/**
 * Extract from T those types that are assignable to U
 */
type Extract<T, U> = T extends U ? T : never;

ReturnType

获取一个函数类型的返回值类型

interface

interface 只能定义对象类型。

type 和 interface 相同之处

都能够用来描述对象或函数

如果是 type

type abc = {
  a: string
  b: number
}

type def = (a: string) => void

如果是 interface

interface adb {
  a: string
  b: number
}

// 因为函数只不过是特殊的对象类型
interface abc {
  (a: string): void
}

都能进行扩展

& 交叉符扩展

类型别名通过 & 交叉符扩展

type def = {
  c: string
}
type abc = {
  a: string
  b: number
}

type foo = def & abc
extends 关键字扩展

接口则通过 extends 关键字进行扩展

interface def {
  c: string
}

interface abc extends def {
  a: string
  b: number
}

const foo: abc = {
  a: '1',
  b: 1,
  c: '123'
}
interface、type 互相扩展

此外,接口也可以通过 extends 来扩展类型别名定义的类型:

type Animal = {
  name: string
}interface Bear extends Animal {
  honey: boolean
}

同样,类型别名也可以通过 &(交叉运算符)来扩展已定义的接口类型:

interface Animal {
  name: string
}type Bear = Animal & { 
  honey: boolean 
}
同名 interface 自动合并扩展

在写它们的不同之处有提到。

type 和 interface 不同之处(自动合并)

1、类型别名可以为基本类型、联合类型或元组类型定义别名,而接口不行

type MyNumber = number;
type StringOrNumber = string | number;
type Point = [number, number];

2、同名接口会自动合并,而类型别名不会

同名接口合并

interface User {
  name: string;
}interface User {
  id: number;
}let user: User = { id: 666, name: "小王" };

同名类型别名会冲突

type User = {
  name: string;
};// 标识符“User”重复。ts(2300)
type User = {
  id: number;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值