基础知识
- 基础类型: number string boolean array object
enum: 枚举
type, interface
联合类型 | (联合类型一次只能一种类型;而交叉类型每次都是多个类型的合并类型。)
交叉类型 & (联合类型一次只能一种类型;而交叉类型每次都是多个类型的合并类型。)
typeof: typeof 操作符可以用来获取一个变量声明或对象的类型
function toArray(x: number): Array<number> {
return [x];
}
type Func = typeof toArray; // -> (x: number) => number[]
- keyof: keyof 操作符可以用来遍历一个对象中的所有 key 值
interface Person {
name: string;
age: number;
}
type K1 = keyof Person; // "name" | "age"
- in: in 用来遍历枚举类型
type Keys = "a" | "b" | "c"
type Obj = {
[p in Keys]: any
} // -> { a: any, b: any, c: any }
- extends : 有时候我们定义的泛型不想过于灵活或者说想继承某些类等,可以通过 extends 关键字添加泛型约束。
interface ILengthwise {
length: number;
}
function loggingIdentity<T extends ILengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
loggingIdentity(3);
loggingIdentity({length: 10, value: 3});
- Paritial
Partial<T> 的作用就是将某个类型里的属性全部变为可选项 ?。
- Reuqired
Required<T> 的作用就是将某个类型里的属性全部变为必选项。
- Readonly
Readonly<T> 的作用是将某个类型所有属性变为只读属性,也就意味着这些属性不能被重新赋值。
- Record
Record<K extends keyof any, T> 的作用是将 K 中所有的属性的值转化为 T 类型。
interface PageInfo {
title: string;
}
type Page = "home" | "about" | "contact";
const x: Record<Page, PageInfo> = {
about: { title: "about" },
contact: { title: "contact" },
home: { title: "home" }
};
- Exclude
Exclude<T, U> 的作用是将某个类型中属于另一个的类型移除掉。
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
- Extract
Extract<T, U> 的作用是从 T 中提取出 U。
type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T1 = Extract<string | number | (() => void), Function>; // () => void
TS编译流程
1、Scanner 扫描器 (scanner.ts)
扫描器的作用就是将源代码生成token流
2、Parser 解析器 (parser.ts)
3、Binder 绑定器 (binder.ts)
符号将 AST 中的声明节点与其它声明连接到相同的实体上。符号是语义系统的基本构造块。
function Symbol(flags: SymbolFlags, name: string) {
this.flags = flags;
this.name = name;
this.declarations = undefined;
}
SymbolFlags 符号标志是个标志枚举,用于识别额外的符号类别(例如:变量作用域标志 FunctionScopedVariable 或 BlockScopedVariable 等).
4. Checker 检查器 (checker.ts)
根据我们生成AST节点的声明起始节点位置,对传进来的字符串做位置类型语法等的校验与异常的抛出。
5.Emitter 发射器 (emitter.ts)
TypeScript 编译器提供了两个发射器:
emitter.ts: 它是 TS -> JavaScript 的发射器
declarationEmitter.ts: 用于为 TypeScript 源文件(.ts) 创建声明文件
常见TS面试题
一、你觉得使用ts的好处是什么?
- TypeScript是JavaScript的加强版,它给JavaScript添加了可选的静态类型和基于类的面向对象编程,它拓展了JavaScript的语法。
- Typescript 是纯面向对象的编程语言,包含类和接口的概念.
- TS 在开发时就能给出编译错误, 而 JS 错误则需要在运行时才能暴露。
- 作为强类型语言,你可以明确知道数据的类型。代码可读性极强。
- ts中有很多很方便的特性, 比如可选链.
二、type 和 interface的异同
- 用interface描述数据结构,用type描述类型
- type 可以声明基本类型别名,联合类型,元组等类型
// 基本类型别名
type Name = string
// 联合类型
interface Dog {
wong();
}
interface Cat {
miao();
}
type Pet = Dog | Cat
// 具体定义数组每个位置的类型
type PetList = [Dog, Pet]
// 当你想获取一个变量的类型时,使用 typeof
let div = document.createElement('div');
type B = typeof div
// type 支持类型映射
type Keys = "firstname" | "surname"
type DudeType = {
[key in Keys]: string
}
const test: DudeType = {
firstname: "Pawel",
surname: "Grzybek"
}
- 都可以描述一个对象或者函数
interface User {
name: string
age: number
}
interface SetUser {
(name: string, age: number): void;
}
type User = {
name: string
age: number
};
type SetUser = (name: string, age: number)=> void;
- 都允许拓展(extends)并且两者并不是相互独立的,也就是说 interface 可以 extends type, type 也可以 extends interface 。
// interface extends interface
interface Name {
name: string;
}
interface User extends Name {
age: number;
}
// type extends type
type Name = {
name: string;
}
type User = Name & { age: number };
// interface extends type
type Name = {
name: string;
}
interface User extends Name {
age: number;
}
// type extends interface
interface Name {
name: string;
}
type User = Name & {
age: number;
}
三、如何基于一个已有类型, 扩展出一个大部分内容相似, 但是有部分区别的类型?
- 通过Pick和Omit
interface Test {
name: string;
sex: number;
height: string;
}
type Sex = Pick<Test, 'sex'>;
const a: Sex = { sex: 1 };
type WithoutSex = Omit<Test, 'sex'>;
const b: WithoutSex = { name: '1111', height: 'sss' };
- Partial, Required
- 通过泛型
四、什么是泛型, 泛型的具体使用?
- 泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,使用时再去指定类型的一种特性。可以把泛型理解为代表类型的参数。
interface Test<T = any> {
userId: T;
}
type TestA = Test<string>;
type TestB = Test<number>;
const a: TestA = {
userId: '111',
};
const b: TestB = {
userId: 2222,
};