这是我参与「第四届青训营 」笔记创作活动的第3天。
What & Why is TypeScript
TypeScript 的特点
- 可读性增强:基于语法解析 TSDoc(自动编写文档),ide 增强。
- 可维护性增强:可以在编译阶段暴露非常多错误。
- 兼容所有 JS 特性。
- 支持渐进式引入与升级,可以让2020年前的 Javascript 库与 TypeScript 项目共存。
TypeScript 的基本语法
基础数据类型
- string
- number
- boolean
- null
- undefined
对象类型
interface IBytedancer {
readonly jobid: number;
name: string;
sex: 'man' | 'woman' | 'other';
age: number;
hobby?: string; // 可选属性
[key: string]: any; // 任意属性
}
const bytedancer: IBytedancer = {
jobId: 12345,
name: 'hello world'
}
函数类型
function add(x: number, y: number): number: {
return x + y;
}
const mult: (x: number, y: number) => number = (x, y) => x * y;
interface IMult {
(x: number, y: number): number;
}
const mult: IMult = (x, y) => x * y;
函数重载
function getDate(type: 'string', timestamp?: string): string;
function getDate(type: 'date', timestamp?: string): Date;
function getDate(type: 'string' | 'date', timestamp?: string): Date | string {
const date = new Date(timestamp);
return type === 'string' ? date.toLocaleString() : date;
}
const x = getDate('date'); // x: Date
const y = getDate('string', '2018-01-10'); // y: string
可以通过 Interface 简化 / 复用函数类型声明
interface IGetDate {
(type: 'string', timestamp?: string): string;
(type: 'date', timestamp?: string): Date;
(type: 'string' | 'date', timestamp?: string): Date | string;
}
const getDate2: IGetDate = (type, timestamp) => {
const date = new Date(timestamp);
return type === 'string' ? date.toLocaleString() : date;
}
上方的类型推断会报错,需要将 IGetDate 返回值的类型范围扩大。
数组类型
type IArr1 = number[];
type IArr2 = Array<string | number | Record<string, number>>;
type IArr3 = [number, number, string, string];
interface IArr4 {
[key: number]: any;
}
const arr1: IArr1 = [1,2,3,4];
const arr2: IArr2 = [1,2,'12',{a:1}];
const arr3: IArr3 = [1,2,'3','4'];
const arr4: IArr4 = [1,2,3,4];
交叉/联合类型
利用|和&将类型进行联合、交叉。
|:可以任选一个类型&:同时需要满足两个类型
联合类型时,只有交集部分可以访问。
解决方式:定义一个守卫类型。
类型守卫
interface IA { a: 1, a1: 2 }
interface IB { b: 1, b1: 2 }
function getIsIA(arg: IA | IB): arg is IA {
return !!(arg as IA).a;
}
function log2(arg: IA | IB) {
// 此时联合类型没有任何交集,无法访问任何元素
if (getIsIA(arg)) { // 此处直接使用 arg.a 来判断会报错
// 此时 typescript 推断 arg 为 IA 类型
console.log(arg.a1);
} else {
// 此时 typescript 推断 arg 为 IB 类型
console.log(arg.b1);
}
}
简化写法
function reverse(target: string | Array<any>) {
if (typeof target === 'string') {
return target.split('').reverse().join('')
}
if (target instanceof Object) { // 剔除了 string 类型
// typescript 可以自动识别出符合的类型
return target.reverse();
}
}
类型保护
type IBookItem = {
author: string;
} & ({
type: 'history';
range: string;
} | {
type: 'story';
theme: string;
})
// or
interface IHistoryBook {
author: string;
type: 'history';
range: string;
}
interface IStoryBook {
author: string;
type: 'story';
theme: string;
}
type IBookItem = IHistoryBook | IStoryBook;
function logBook(book: IBookItem) {
if (book.type === 'history') {
console.log(book.range);
} else {
console.log(book.theme);
}
}
高级类型
function merge1(sourceObj, targetObj) {
const result = { ...sourceObj };
for (let key in targetObj) {
const itemVal = sourceObj[key];
itemVal && ( result[key] = itemVal );
}
return result;
}
function merge2(sourceObj, targetObj) {
return { ...sourceObj, ...targetObj };
}
// 缺点
// 1. 实现比较繁琐:所有类型需要写两遍
// 2. 修改比较繁琐:所有类型需要改两遍
// 3. 不完善:无法处理 any 类型。
interface ISourceObj {
x?: string;
y?: string;
}
interface ITargetObj {
x: string;
y: string;
}
type IMerge =
(sourceObj: ISourceObj, targetObj: ITargetObj) => ITargetObj;
interface IMerge {
<T extends Record<string, any>>
(sourceObj: Partial<T>, targetObj: T): T;
}
// `T extends Record<string, any>`
// 限定 T 类型需要是一个 string 为 key 的 object。
type IPartial<T extends Record<string, any>> = {
// T 是一个 key 永远为 string,value 任意的 object
[P in keyof T]?: T[P];
// `keyof T` 指的是 T 中的所有 key 联合起来的字面量
// 如 `keyof { a: string; b: number }` 即为 `'a' | 'b'`
// [ P in keyof T ] 指的是 P 是 T 的任意一个 key ('a' 或 'b')
// [ P in keyof T ]: T[P] 指 P 作为 key,对应 T 里面的 value 类型。
// [ P in keyof T ]?: T[P] 指不需要所有 key,任意选择一些即可
}
// Partial 已经是内置类型了
函数的返回值
function delayCall(func) {
return new Promise(resolve => {
setTimeout(() => {
const result = func();
resolve(result);
}, 1000);
});
} // 1000ms 之后调用 func 函数
// 定义类型
type IDelayCall = <T extends () => any>(func: T) => IReturnType<T>;
type IReturnType<T extends (...args: any) => any> = T extends (...args:any) => infer R ? R : any;
工程应用
浏览器 Web 应用
主要使用 webpack:
- 配置webpack loader,将 typescript 转化为 javascript 文件。
- tsconfig.js 加强对代码的约束。
- 运行 webpack 进行打包。
Node 应用
使用 tsc 编译运行:
- node 环境。
- tsconfig.js 文件配置。
- tsc 运行编译得到 .js 文件。