1、声明文件和declare关键字
处理问题:当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。这是因为前端第三方库大多都是非 TypeScript 库,基本上都是使用 JS 编写的,在 TS 中使用非 TS 编写的第三方库,需要有个 xx.d.ts 声明文件。
注意:.d.ts 文件中的顶级声明必须以 "declare" 或 "export" 修饰符开头。
declare 就是申明一个全局的类型或者变量或者模块
// 例1 声明一个类型
declare type Asd {
name: string;
}
// 例2 申明一个模块
declare module "*.vue" {
import Vue from 'vue'
export default Vue
}
2..d.ts是干嘛的?
用途:.d.ts文件是ts用来声明变量,模块,type,interface等等的。
引用:在.d.ts声明变量或者模块等东西之后,在其他地方可以不用import导入这些东西就可以直接用,用,而且有语法提示。需要预编译,所以需要在tsconfig.json文件里面的include数组里面添加这个文件
3 、ts工具函数
交叉类型(&)
通过 & 将多个类型合并为一个类型
T & U
function extend<T , U>(first: T, second: U) : T & U {
let result: <T & U> = {}
for (let key in first) {
result[key] = first[key]
}
for (let key in second) {
if(!result.hasOwnProperty(key)) {
result[key] = second[key]
}
}
return result
}
Partial : 将选入的属性变为可选项(全局变可选)
首先我们需要理解两个关键字 keyof 和 in, keyof 可以用来取得一个对象接口的所有 key 值.
interface Foo {
name: string;
age: number
}
type T = keyof Foo // -> "name" | "age"
而 in 则可以遍历枚举类型, 例如:
type Keys = "a" | "b"
type Obj = {
[p in Keys]: any
} // -> { a: any, b: any }
Partial源码
type Partial<T> = { [P in keyof T]?: T[P] };
Required将传入的属性变为必选项
Required源码
type Required<T> = { [P in keyof T]-?: T[P] };
注意:我们发现一个有意思的用法 -?, 这里很好理解就是将可选项代表的 ? 去掉, 从而让这个类型变成必选项. 与之对应的还有个+? , 这个含义自然与-?之前相反, 它是用来把属性变成可选项的.
Mutable (未包含)
类似地, 其实还有对 + 和 -, 这里要说的不是变量的之间的进行加减而是对 readonly 进行加减.
以下代码的作用就是将 T 的所有属性的 readonly 移除,你也可以写一个相反的出来.
Mutable源码
type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}
Readonly
将传入的属性变为只读选项, 源码如下
Readonly源码
type Readonly<T> = { readonly [P in keyof T]: T[P] };
Record
将 K 中所有的属性的值转化为 T 类型
Record源码
type Record<K extends keyof any, T> = { [P in K]: T };
Pick
从 T 中取出 一系列 K 的属性
Pick源码
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
Exclude
从T 中排除 U
在 ts 2.8 中引入了一个条件类型, 示例如下
T extends U ? X : Y
以上语句的意思就是 如果 T 是 U 的子类型的话,那么就会返回 X,否则返回 Y
Exclude源码
type Exclude<T, U> = T extends U ? never : T;
Extract
从 T 中提取出 U
Extract源码
type Extract<T, U> = T extends U ? T : never;
Omit (未包含)
用之前的 Pick 和 Exclude 进行组合, 实现忽略对象某些属性功能
Omit源码
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>
// 使用
type Foo = Omit<{name: string, age: number}, 'name'> // -> { age: number }
ReturnType我们可以用它获取函数的返回类型
infer 关键字
在条件类型语句中, 我们可以用 infer 声明一个类型变量并且对它进行使用,
源码
type ReturnType<T> = T extends (
...args: any[]
) => infer R
? R
: any;
具体用法
function foo(x: number): Array<number> {
return [x];
}
type fn = ReturnType<typeof foo>;
AxiosReturnType(未包含)
开发经常使用 axios 进行封装 API层 请求, 通常是一个函数返回一个 AxiosPromise<Resp>, 现在我想取到它的 Resp 类型, 根据上一个工具泛型的知识我们可以这样写.
import { AxiosPromise } from 'axios' // 导入接口
type AxiosReturnType<T> = T extends (...args: any[]) => AxiosPromise<infer R> ? R : any
// 使用
type Resp = AxiosReturnType<Api> // 泛型参数中传入你的 Api 请求函数
4、忽略 undefined 和 null 类型
x! 将从 x 值域中排除 null 和 undefined 。
例子如下
function myFunc(maybeString: string | undefined | null) {
// Type 'string | null | undefined' is not assignable to type 'string'.
// Type 'undefined' is not assignable to type 'string'.
const onlyString: string = maybeString; // Error
const ignoreUndefinedAndNull: string = maybeString!; // Ok
}
5、调用函数时忽略 undefined 类型
const num2 = numGenerator!(); //OK
type NumGenerator = () => number;
function myFunc(numGenerator: NumGenerator | undefined) {
// Object is possibly 'undefined'.(2532)
// Cannot invoke an object which is possibly 'undefined'.(2722)
const num1 = numGenerator(); // Error
const num2 = numGenerator!(); //OK
}
6、确定赋值断言
let x!: number;
initialize();
console.log(2 * x); // Ok
function initialize() {
x = 10;
}
通过 let x!: number; 确定赋值断言,TypeScript 编译器就会知道该属性会被明确地赋值。
7、typeof 关键字
typeof 类型保护只支持两种形式:typeof v === "typename" 和 typeof v !== typename,"typename" 必须是 "number", "string", "boolean" 或 "symbol"。 但是 TypeScript 并不会阻止你与其它字符串比较,语言不会把那些表达式识别为类型保护。
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
8、类型约束
通过关键字 extend 进行约束,不同于在 class 后使用 extends 的继承作用,泛型内使用的主要作用是对泛型加以约束
引用
type BaseType = string | number | boolean
// 这里表示 copy 的参数
// 只能是字符串、数字、布尔这几种基础类型
function copy<T extends BaseType>(arg: T): T {
return arg
}
9、条件类型
条件类型的语法规则和三元表达式一致,经常用于一些类型不确定的情况。
//意思就是,如果 T 是 U 的子集,就是类型 X,否则为类型 Y
T extends U ? X : Y
10、ts 函数重载
允许创建数项名称相同但输入输出类型或个数不同的子程序,它可以简单地称为一个单独功能可以执行多项任务的能力
引用
关于typescript函数重载,必须要把精确的定义放在前面,最后函数实现时,需要使用 |操作符或者?操作符,把所有可能的输入类型全部包含进去
// 上边是声明
function add (arg1: string, arg2: string): string
function add (arg1: number, arg2: number): number
// 因为我们在下边有具体函数的实现,所以这里并不需要添加 declare 关键字
// 下边是实现
function add (arg1: string | number, arg2: string | number) {
// 在实现上我们要注意严格判断两个参数的类型是否相等,而不能简单的写一个 arg1 + arg2
if (typeof arg1 === 'string' && typeof arg2 === 'string') {
return arg1 + arg2
} else if (typeof arg1 === 'number' && typeof arg2 === 'number') {
return arg1 + arg2
}
}
11、泛型参数默认类型
概念:在 TypeScript 2.3 以后,我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推断出类型时,这个默认类型就会起作用。
语法:<T=Default Type>
示例:
interface A<T=string> {
name: T;
}
const strA: A = { name: "Semlinker" };
const numB: A<number> = { name: 101 };
12、Record定义一个对象的 key 和 value 类型
示例:比如我需要一个对象,有 ABC 三个属性,属性的值必须是数字,那么就这么写:
type keys = 'A' | 'B' | 'C'
const result: Record<keys, number> = {
A: 1,
B: 2,
C: 3
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。