还是上次面试失利后,
1.感觉自己只是单纯的会用某种技术不会表达含义,资方就认为你不会。
2.专业一点的产品,还是会选择ts。
ts是js的超集,在兼容js的同时,带来了类似java c#等语言才具有的强类型定义特点,不仅可以使用常见的js语法
还可以充分利用js不具备的强类型定义,泛型,面对对象等ts拓展功能构建更强大,更健壮易维护的项目。
一.类型注解(基本知识)
TypeScript里的类型注解是一种轻量级的为函数或变量添加约束的方式
1.定义数组
let list : number[] = [1,2,3];
//or
let list : Array<number> = [1,2,3];
2.定义元组类型(元组类型表示允许数组内的类型各不相同,但是在赋值时需要按照类型顺序来赋值)
let list : [string , number];
x = ['hello', 24]; // true
x = [20 , 'hello']; // false
!!!当访问一个跨界元素时,会使用联合类型进行替代,但不能尝试赋值已有类型以外的
a.类型注解中有哪些类型?
1. 基础的类型 2. 数组 3. 元组 4. 枚举 5. Any 6. void 7. null和undefined 8. never 9. Object类型 10. 类型断言
a.1.any
保持js的语言灵活性,带来强类型语言带来的高维护性。
a.2unknown
不保证类型,但是保证类型安全。(需要确定变量类型,才能正常使用)
a.void(压根不存在)
函数没有返回值,函数就是void类型
a.undefined(不存在初始值)
存在,但是不存在初始值
a.never(处理异常 promise 控制逻辑流程)
一个函数执行不完,就是never 比如throw / while
never
类型表示的是值永远不会出现的一种类型
type A = 'A';
type B = 'B';
type C = A & B;
C的类型就是 never
1.never
类型可以用于声明函数的返回值类型,表示该函数不会有任何返回值
当然,void
类型也可以用于声明函数的返回值类型来表示函数没有任何返回值,但是 void
所表示的意思就不那么明确了。使用 void
的话,函数是可以返回 undefined
的,而采用 never
则不允许函数返回 undefined
。
function a(): void {
return undefined; // 一切正常
}
function b(): never {
return undefined; // 类型 'undefined' 不能分配给类型 'never'
}
a 类型断言(类型适配)
let message:any;
message='abc'
// message 赋值字符串,类型还是any类型(此处没有智能方法补充)
message.endWith('c')
//更改message类型-类型适配
let str = (<string>message).endWith('c')
// 第二种方法
let str1 =(message as string).endWith('c')
a.函数类型
## 泛型约束
泛型可以通过 extends 一个接口来实现泛型约束,写法如:<泛型变量 extends 接口>
,例子:
```
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) // 自动类型推导,允许
```
二.type 和 interface 的区别
type
和 interface
,都可以给类型命名并通过该名字来引用表示的类型
TYPE
type
关键字是声明类型别名的关键字
interface
通过关键字 interface
可以定义一个接口类型。它能合并众多类型声明至一个类型声明。
接口声明只存在于编译阶段,在编译后生成的 JS 代码中不包含任何接口代码。
!!! 接口名,首字母需要大写
相同点:
- 都可以用来定义 对象 或者 函数 的结构,而严谨的来说,type 是引用,而
interface
是定义
不同点:
- type 在声明类型别名之后实际上是一个赋值操作,它需要将别名与类型关联起来。也就是说类型别名不会创建出一种新的类型,它只是给已有类型命名并直接进行引用。
interface
是定义了一个接口类型。 - interface 定义重名了会合并属性,type 办不到(会报错提醒 重复定义)
interface
可以继承其他的接口、类等对象类型, type 不支持继承- type 能够表示非对象类型, 而
interface
则只能表示对象类型
type总结:
- 一般定义基本或联合类型
- 一般定义元组类型
- 一般定义函数类型
- 定义映射类型
interface 总结:
- 需要interface 重名会自动合并属性扩展的
- 在对于对象结构的类型定义上,建议尽可能的使用
interface
,而在合适的场景使用type
关联:
TS篇—type 和 interface 的区别_learning_H的博客-CSDN博客_ts type
TypeScript type 和 interface区别_天渺工作室的博客-CSDN博客_typescript中type和interface的区别
三. 实用ts技巧
1.善用声明文件
1.1 只要 tsconfig.json
中的配置包含了 typing.d.ts
文件,那么其他所有 *.ts
文件就都可以获得声明文件中的类型定义
1.2 第三方声明文件
当在 TypeScript
项目中使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
针对多数第三方库,社区已经帮我们定义好了它们的声明文件,我们可以直接下载下来使用。一般推荐使用 @types
统一管理第三方库的声明文件,@types
的使用方式很简单,直接用 npm
或 yarn
安装对应的声明模块即可
1.3 自定义声明文件 (三方无声明文件)
当一个第三方库没有提供声明文件时,我们就需要自己书写声明文件。以 antd-dayjs-webpack-plugin
为例,当在 config.ts
中使用 antd-dayjs-webpack-plugin
时,若当编辑器没有找到它的声明文件。则会报错
为了解决编辑器的报错提示,我们可以采用它提供的另一种方法:添加一个包含 declare module 'antd-dayjs-webpack-plugin';
的新声明文件。我们也可以不用新增文件,在前面提到的 typing.d.ts
添加下面的内容即可
1.4 全局变量的命名空间
不同.d.ts 中 interface 命名冲突
a.d.ts
declare namespace A {
interface Test {}
}
b.d.ts
declare namespace B {
interface Test {}
}
//use
const domain : A.test = {}
const domain : B.test = {}
2.善用扩展
3.善用注释
4.善用访问限定修饰符(在类的声明中使用)
TypeScript
的类定义允许使用private
、protected
和public
这三种访问修饰符声明成员访问限制,并在编译期进行检查:
public
: 公有类型,在类里面、子类、类外面都可以访问到,如果不加任何修饰符,默认为此访问级别;protected
: 保护类型,在类里面、子类里面可以访问,在类外部不能访问;private
: 私有类型,只能在当前类内部访问。
参考:https://zhuanlan.zhihu.com/p/613100229
5.善用类型收窄
5.1 类型断言
animal as Cat
把一个值断言为一个类型 值 as 类型
虽然可以对值进行类型指定 但是有风险 因为这个做法只是绕过ts类型校验
并不能避免运行时报错 滥用会导致维护性差
5.2类型守卫
- 类型守卫主要有以下几种方式:
- typeof:用于判断
number
,string
,boolean
或symbol
四种类型; - instanceof:用于判断一个实例是否属于某个类
- in:用于判断一个属性/方法是否属于某个对象
- typeof:用于判断
他们共同解决的问题 就是联合类型有多种 他们通过判断 收窄类型
5.3 双重断言
除非迫不得已,千万别用双重断言
5.4 善用常量枚举
普通枚举的值不会在编译阶段计算,而是保留到程序的执行阶段(不用const)
常数枚举与普通枚举的区别是,前者会在编译阶段被移除,并且不能包含计算成员(即常量枚举成员初始值设定项只能包含文字值和其他计算的枚举值)
可以看到,当我们不需要一个对象,而需要对象的值,就可以使用常数枚举,这样就可以避免在编译时生成多余的代码和间接引用。
5.5 善用高级类型
5.5.1 类型索引(keyof)
keyof
类似于 Object.keys
,用于获取一个接口中 Key 的联合类型
5.5.2 类型约束(extends)
TypeScript
中的 extends
关键词不同于在 Class
后使用 extends
的继承作用,一般在泛型内使用,它主要作用是对泛型加以约束
extends
经常与 keyof
一起使用,例如我们有一个 getValue
方法专门用来获取对象的值,但是这个对象并不确定,我们就可以使用 extends
和 keyof
进行约束:
function test<T, K extends keysof T>(a: T, b: K): void {}
当传入对象没有的 key
时,编辑器则会报错。