这是我参与「第五届青训营」伴学笔记创作活动的第 4 天。
更棒的一份参考笔记:
为什么需要TypeScript(TS)?
- 由微软开发
- 主流框架(React、Vue)均受支持
- 推荐编辑器:Visual Studio Code
| JavaScript | TypeScript |
|---|---|
| 动态类型 | 静态类型 |
| 弱类型类型 | 弱类型类型 |
- 动态类型:在运行期才判断类型
- 静态类型:在编译时就判断类型
- 弱类型语言:容许隐式类型转换
【TS的语言优势】
-
采用静态类型
- 可读性增强:基于语法解析TSDoc,IDE增强(类型提示/语法补全)
- 可维护性增强:在编译阶段暴露大部分错误
在多人合作的大型项目中可以获得更好的稳定性和开发效率
-
是 JS 的超集
- 包含于兼容所有Js特性,支持共存
- 支持渐进式引入与升级
TS基本语法
基础数据类型
/* 字符串 */
const q = 'string';
/* 数字 */
const w = 1;
/*布尔值*/
const e = true;
/* null*/
const r = null;
/* undefined */
const t = undefined;
添加上类型标注后,就形成了等价的TS:
/* 字符串 */
const q: string = 'string';
/* 数字 */
const w: number = 1;
/*布尔值*/
const e: boolean = true;
/* null*/
const r: null = null;
/* undefined */
const t: undefined = undefined;
对象类型
interface(接口)是TS设计出来用于定义对象类型的,可以对对象的属性进行描述。它不是 JS 中的关键字。
接口的命名通常以大写I开头。
接口中可以定义:
- 只读属性:约束属性不可在对象初始化外赋值
- 可选属性:定义该属性可以不存在
- 任意属性:约束所有对象属性都必须是该属性的子类型
interface IBytedancer {
/* 只读属性 */
readonly jobId: number;
name: string;
sex:'man' | 'woman' | 'other';
age: number
/* 可选属性 */
hobby?: string;
/* 任意属性 */
[key: string]: any;
}
const bytedancer: IBytedancer ={
jobId: 9303245
name: 'Lin',
sex: 'man',
age: 28,
hobby:'swimming',
}
/* 报错:无法分配到"jobId",因为它是只读属性 */
bytedancer.jobId = 12345;
/* 成功:任意属性标注下可以添加任意属性 */
bytedancer.plateform = 'data';
/* 报错:缺少属性"name",hobby可缺省 */
const bytedancer2: IBytedancer = {
jobId: 89757,
sex: 'woman',
age: 18,
}
函数类型
-
直接定义函数
/* 直接定义函数 */ 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;
利用接口也可以实现函数重载:
interface IGetDate {
(type: 'string', timestamp?: string): string;
(type: 'date', timestamp?: string): Date;
(type: 'string' | 'date', timestamp?: string): string | Date;
}
/* 报错 */
const getDate: IGetDate = (type, timestamp) => {
const date = new Date(timestamp);
return type === 'string' ? date.toLocaleString() : date;
}
这里似乎有点问题,还在等待老师回复……
数组类型
利用
type关键字可以定义类型别名。
- “类型+方括号”表示【常用】
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, 5, 6];
const arr2: IArr2 = [1, 2, '3', '4', { a: 1 }];
const arr3: IArr3 = [1, 2, '3', '4'];
const arr4: IArr4 = ['string', () => null, {}, []];
其他类型
-
空类型:表示无返回值
type IEmptyFunction = () => void; -
任意类型:是所有类型的子类型
type IAnyType = any; -
枚举类型:支持枚举值与枚举名的双向映射
enum EnumExample { add = '+', mult = '*', } EnumExample['add'] === '+'; EnumExample['+'] === 'add';
泛型
泛型:不预先指定具体的类型,而是在使用时再推断/指定类型
// 生成一个重复给定元素100次的数组
type IGetRepeatArrR = <T>(target: T) => T[];
const getRepeatArr: IGetRepeatArrR = (target) => {
return Array(100).fill(target);
}
这样一来,getRepeatArr(1)返回的就是number[]类型。
TS中不需要像C++一样每次使用都明确指定泛型中的T是什么类型,TS可以自行推断。
除了函数、接口、类、别名也可以是泛型,甚至泛型中的类型placeholder还可以是多个:
/* 泛型接口 & 多泛型 */
interface IX<T, U> {
key: T;
val: U;
}
/* 泛型类 */
class IMan<T> {
instance: T;
}
/* 泛型别名 */
type ITypeArr<T> = Array<T>;
泛型约束:可以对泛型的类型placeholder做约束
type IGetRepeatStringArr = <T extends string>(target: T) => T[];
const getStrArr: IGetRepeatStringArr = target => new Array(100).fill(target);
泛型参数默认值:可以对泛型的类型placeholder设置默认值
type IGetRepeatArr<T = number> = (target: T) => T[];
const getStrNumArr: IGetRepeatArr= target => new Array(100).fill(target);
const getStrStrArr: IGetRepeatArr<string> = target => new Array(100).fill(target);
let a = getStrNumArr("1"); // 报错
let b = getStrStrArr("1"); // 正常
类型断言
通过as关键字,可以断言(修改)推断出的类型:
let a: any = [1, 2, 3];
let b: number = (a as number[]).reduce(v => v);
字符串/数 字面量 多选一
type IDomTag = "html" | "body" | "div";