前言
在面试和复习过程中总结的一些前端知识点,记录下来,风格较简洁,尽量涵盖内容要点和简单例子。本文是前端面试系列第二篇:TypeScript 相关要点,持续更新...
一、Typescript 的概念
TypeScript(简称 TS) 是微软开发的一个开源的编程语言,通过在 JavaScript 的基础上添加静态类型定义构建而成。TypeScript 通过 TypeScript编译器 或 Babel 转译为 JavaScript 代码,可运行在任何浏览器,任何操作系统。
TS 的优势:
- 可识别类型错误、拼写错误;
- 可自动联想;
- 类型可充当文档,提高代码可读性;
二、TS 中的一些对比
1. const vs readonly
- const 表示声明了一个常量,值不可变;
- readonly 用于 class 中,表示声明了一个只读属性,值不可变
2. interface vs type
相同点:
- 都可以定义:对象、函数
- 都支持继承
不同点:
- interface 可以 重复声明,并把多次声明的结果合并
interface i1 { a: Number } interface i1 { b: String } // 实际上 i1 为 { a: Number; b: String } - type 可以定义 基本类型,如
Number、String、Boolean - type 可以通过 typeof 操作符来定义,如
type t1 = typeof obj1 - type 可以申明 联合类型,如
type t1 = t2 | t3 - type 可以申明 元组类型,如
type t1 = [t2, t3]
3. extends vs implements
- extents 是子类继承父类的所有属性和方法
- implements 是一个类对一个接口的实现,它必须满足接口的所有规范
interface Person { money: Number }
class Father implements Person {
public money: Number = 100
}
class Son extends Father {
constructor() {
super();
}
getMoney(): Number {
return this.money;
}
}
4. declare vs declare global
declare在声明文件中定义全局类型,这样其它模块代码都可以用到该类型// global.d.ts declare var n: number; declare let s: string;declare global用于修改 已存在 的全局变量的声明// 给全局 String 类型增加 hump 方法 declare global { interface String { hump(input: string): string; } } // 注意: 修改全局声明必须在模块内部, 所以至少要有 export{} 字样 export {}
5. any 、unknown、void、never
any可以跳过类型检查,任何类型都可以赋值给 any,反之也成立,这样就失去了类型检查的意义,慎用!unknown是所有类型的父类,任何类型都可以赋值给 unknown,但反之不成立,unknown 在赋值给其它变量前必须要先判断自己是什么类型才能继续使用。通常的使用场景是如果暂时不知道变量是什么类型可以先声明为 unknown,然后再根据后面的判断把它转化为想要的类型。- 用
void声明一个变量,则它只能被赋值 undefined 或 null - never 和 void 的混淆点在于它俩用于函数时都表示没有返回值,区别在于:
void表示函数是正常运行的,本身设计就不存在返回值;never表示函数出现异常,比如抛出错误或死循环,存在无法到达的终点;
function func1(): void { console.log(111) } function func2(): never { while (true) { } }
6. ?.、!、??、_、**
?.当左侧出现 undefined 或 null 时会自动停止运行表达式const a = b?.c // 当b为空值时,该表达式也不会报错!非空断言运算符,将从自身类型中排除 null 和 undefinedconst a: { x?: number } = { x: 1 }; // 报错:Type 'number | undefined' is not assignable to type 'number' const b: number = a.x; // 不会报错,当明确 a.x 在这里实际有值时可以加 ! const c: number = a.x!;??空值合并运算符,它和||的区别是:a ?? b // 当 a 是 undefined 或 null 时,表达式结果为 b,否则为 a a || b // 当 a 转化成 bool 值为 false 时,表达式结果为 b,否则为 a_数字分隔符不会改变数字字面量的值,使人更容易读懂数字1_111_111 // 实际上就是 1111111,数字分隔符可以增加可读性**幂运算3**2 // 结果为 9
6. Exclude、Omit
Exclude<T, U>从类型集 T 中剔除类型集 Utype T0 = Exclude<"a" | "b" | "c", "a">; // T0 = "b" | "c"Omit<T, K>从 T 的所有属性中剔除 K 属性interface Todo { title: string; description: string; } type TodoPreview = Omit<Todo, "description">; // TodoPreview = { title: string }
三、interface
1. interface 描述函数类型
interface ICompare {
(a: number, b: number): boolean
}
const compareFunc: ICompare = (a, b) => a > b;
2. interface 描述可索引类型
可索引类型通常指 数组 和 对象 :
interface IArray {
[index: number]: string;
}
let myArray: IArray = ["Bob", "Fred"];
interface IObject {
[key: string]: string;
}
let myObject: IObject = { a: '11', b: '22' };
四、联合类型
- 联合类型包含了变量可能的所有类型,例:
let res: number | string; - 对联合类型变量赋值为联合类型之外的值,会报错;
- 在不能确定联合类型变量的最终类型之前,只能访问联合类型所共有的属性和方法,如上述例子中如果调用
res.length就会报错,但如果类型推断能确定res的类型是string,则不会报错。
五、泛型
-
用来创建可重用的组件,一个组件可以支持多种类型的数据,这样用户就可以以自己的数据类型来使用组件。简单的说,泛型就是把类型当成参数。例:
function identity <T, U>(value: T, message: U) : T { console.log(message); return value; } identity<Number, string>(68, “hello”); -
调用时可以不传类型,编译器能够自动选择这些类型:
identity(68, "hello") -
泛型接口:
interface Identities<V, M> { value: V, message: M } function identity<T, U> (value: T, message: U): Identities<T, U> { return { value, message }; } identity(68, "hello”); -
泛型类:
class IdentityClass<T> { value: T constructor(value: T) { this.value = value } getIdentity(): T { return this.value } } const myNumberClass = new IdentityClass<Number>(68); -
确保属性存在
interface Length { length: number; } function identity<T extends Length>(arg: T): T { console.log(arg.length); return arg; }这样一来,identity 只能接受有 length 属性的参数了
-
检查对象上的键是否存在
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; }