1. 对 TypeScript 的理解
typescript 是静态类型语言,它向 js 添加了类型语法,可以提前检测出错误,提高代码的质量和健壮性。
TS 和 JS 的区别在于静态类型语言(变量声明时类型就是确定的,之后不允许再修改)和动态类型语言(运行阶段才会确定变量类型,变量类型随时可改变)。
补充:和 java/c++ 这种静态强类型语言不同,ts 能够兼容 js 语法,所以是静态、弱类型语言。TS 会被编译成 JS 再运行。
- TS 跨平台:可应用在任何操作系统上,linux、windows、mac...
- ES6 特性:TS 支持 ES6 的大部分特性
- TS 是面向对象的语言
2. mudule 和 namespace 的区别
module:包含顶级import或export的文件都被当作一个模块,如果文件中两者都不包含,那么它的内容视为全局可见的。
namespace:namespace是全局namespace下的一个 JS 对象,主要是为了避免命名冲突,不同命名空间中的标识符不会发生冲突。
区别在于 module 可以声明它的依赖、可以更好地复用代码,而 namespace 很难识别组件之间的依赖关系,后期的维护成本高。 因此大型应用不推荐使用 namespace。
补充:.ts的文件最后会编译成.js文件,这时候类型信息就丢失了,.d.ts文件可以在写js代码时提供一些类型信息。
3. 对泛型的理解
泛型<T>允许将类型作为参数进行传递以创建可重用的组件,让该组件不仅能支持当前的数据类型,也能支持未来的数据类型。
// “类型变量 T” 捕获用户传入的类型,之后就可以使用这个类型
function identity<T>(args: T): T {
return args;
}
// 泛型类
class GenericNumber<T> {
value: T;
add: (x: T, y: T) => T;
}
let geNumber = new GenericNumber<number>();
// 泛型约束,限制函数去处理带有 .length 属性的所有类型
interface Lengthwise {
length: number;
}
function identity<T extends Lengthwise>(args: T): T {
console.log(args.length);
return args;
}
4. 枚举、联合类型、交叉类型、元组、字面量类型
使用枚举类型enum可以定义一些带名字的常量,并将取值限定在一定范围内。成员默认从 0 开始递增。
和普通枚举相比,常量枚举不支持动态计算,并且常量枚举在编译阶段会被删除、避免性能消耗。
enum state {
error = "ERROR",
success = "SUCCESS"
}
// 常量枚举,会严格地限制访问
const enum Directions {
Up = 1,
Down
}
联合类型|的取值可以是多种类型中的一种。当访问联合类型的值时,只能访问所有类型共有的成员。
let tmp = string | number;
交叉类型&会将多个类型合并为一个类型,合并后的对象将拥有所有类型的成员。
type Response = Person & Loggable & ArtData;
Tuple元组类型[string, number]表示一个已知元素数量和类型的数组,各元素的类型不需要相同。
let tmp: [string: number] = ['Tom', 25];
字面量类型有三种:字符串、数字和布尔值。
5. 类型别名 type 和 Interface 的区别
type用于给一个类型起新的名字。
type Point = {
x: number;
y: number;
}
interface用于描述一个对象的结构和类型,在前后端开发时起到一个约定的作用。也可以给函数、数组、类做声明。
interface Person {
readonly id: number; // 只读属性
name: string; // 必须属性
age?: number; // 可选属性
}
两者区别:
- type 可以声明基本类型、联合类型、元组等;
- Interface 的声明重名时可以合并,type 重名会报错。
6. any 和 unknown
两者都用于描述不确定的类型,更推荐使用unknown。
unknown的变量在使用前需要先进行类型判断(typeof)来缩小类型范围,因此比较安全。- 任何类型都可以分配给
any和unknown。any可以分配给任何类型,但unknown只能分配给unknown或any。 any和任何类型T的交叉类型为any,unknown和任何类型T的交叉类型为T。- (忽略)
any和任何类型T的联合类型为any,unknown和任何类型T的联合类型为unknown。
function fn(x: unknown) {
let v1: any = x;
let v2: unknown = x;
let v3: string = x; // Error
}
7. never 和 void
- 含义:
void表示没有任何类型,never表示永不存在的值的类型。 - 函数返回值:当一个函数返回空值时,返回值为
void类型;当一个函数根本没有返回值时(或抛出异常),返回值为never类型。 - never 是所有类型的子类型。
8. const 和 readonly
- const 用于变量,readonly 用于属性。
- 当用于对象时,readonly 表示对象属性不能改变,而 const 表示对象引用不改变、属性可变。
9. infer 关键字
infer表示类型推导,只能用在 extends 语句、声明的变量只能用在 true 分支。它会在类型没有推导时进行占位,等到推导成功后就返回正确的类型。
T extends (...args: any) => infer P
- 忽略
infer P而从整体来看,这段代码实际表示 T 是不是一个函数类型; (...args: any) => infer P这段代码实际表示一个函数类型,其中使用P将返回类型进行占位;- 如果 T 是函数类型,那么返回函数的返回类型
P;如果不是函数类型就返回never。
10. 类和访问修饰符
extends会从父类中继承属性和方法。
访问修饰符决定了类成员的可访问性,共有三种:
- 默认
public:类中的所有成员、其子类和类的实例都可以被访问; private:不能在类的外部访问;protected:和 private 区别在于protected的成员可以被子类中访问(但在该类的实例中无法访问)。
readonly是只读修饰符,不是访问修饰符。
11. extends 和 implements 的区别
- 使用 implements 的类需要实现相关类的所有属性和方法;
- 使用 extends 的子类会继承父类的所有属性和方法。
12. TS 中的方法重载
方法重载是指在一个类中定义多个同名的方法,但每个方法具有不同数量的参数或者参数类型不同。
- 方法重载能够对功能相似的方法进行统一,更容易记住。
- 重载方法应该完成类似的功能。
- 重载方法的返回值类型应该相同。
13. 类型断言Assertion
当你知道某个值更具体的类型时,可以通过类型断言as告诉编译器,手动指定更具体的类型。
let v1: any = "this is a string";
// 推荐写法:值 as 类型
let vLength: number = (v1 as string).length;
// 其他写法:<类型>值
let vLength: number = (<string>v1).length;
14. 实用工具类型
Partial<T>:将类型 T 的所有属性都设置为可选的,返回类型是输入类型的子集。Required<T>:和 Partial 相反,所有属性都是必选的。Readonly<T>:将类型 T 的所有属性都设置为可读的、不能修改。Pick<T, K>:从 T 中挑选出属性 K。Omit<T, K>:从 T 中移除属性 K。Exclude<T, ExcludedUnion>:移除 T 中的 U 集合属性。Extract<T, Union>:Exclude 的反操作,取 T、U 的交集属性。Record<Keys, Type>:构造一个类型,key 的类型为 K,value 的类型为 T。Parameters<T>:获取一个函数的所有参数类型。ReturnType<T>:由函数类型 T 的返回值类型构建出的新类型。ConstructorParameters<T>:获取一个类的构造函数参数类型。InstanceType<T>:由构造函数类型 T 的实例类型构建出的新类型。NonNullable<T>:从类型 T 中移除 null、undefined 属性。
15. TS 中的类型
- number、string、boolean、void、null、undefined
- enum、interface、tuple、array、class...
16. declare 关键字
因为 JS库或框架 中是没有 TS 声明文件的,我们在 TS 中使用它们时需要加declare以避免编译错误。这时 TS 运行时会把声明的库变量赋值为any类型,跳过编译检查。
import 'vue-router'
declare module 'vue-router' {
//...
}
17. 使用TS判断某函数的传入参数是否为数组类型
function isArray(x: unknown): boolean {
if (Array.isArray(x)) return true;
return false;
}
18. ?. / ?? / ! 等符号的含义
?.可选链运算符可以读取对象的深层属性,而且不用验证引用是否有效。当遇到null、undefined时会结束运行,此时返回值是undefined。??空值合并运算符。当左侧操作数为null、undefined时返回右侧操作数,否则返回左侧操作数。!,!x将从 x 值域中排除null、undefined。
19. 装饰器 Decorator
装饰器是一种特殊类型的声明,可以被附加到类声明、方法/属性、访问符或参数上。
使用@expression的形式,在不改变原类、继承的情况下动态地扩展对象功能。
20. tsconfig.json 有什么作用
可以设置不同的选项来告诉编译器如何编译当前项目。
- include:需要包含的文件;
- exclude:要排除的文件。
参考: