前端与 TypeScript入门 | 青训营笔记

55 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天.

今日笔记重点内容:

  1. 了解强类型、弱类型以及静态类型、动态类型
  2. 了解TS的数据类型
  3. 学习TS的泛型

JS起初没有想到会发展得如此广泛,JS没有编译的环节(因此只能是弱类型的,因为强类型在编译阶段就会报错) 而起初这些都是JS的优点,因为方便快捷,而随着规模变大,也成了他的缺点。

在了解TS之前,先了解一下强弱类型以及静态动态类型的概念!

强弱类型&&静动态类型

类型安全: 强类型 弱类型 在编码时,函数是否会自动隐形类型转换,如果不会就是强类型,如果会,就是弱类型。比如 '100' - 50 在JS里,能够直接得到答案,就是50 而Python里则会报错。 因此JS是弱类型,而Python是强类型

类型检查: 静态类型 动态类型 是否允许随意去修改变量的类型。 在定义的时候就决定了变量的类型,就是静态类型 在动态类型里,变量是没有类型的,变量里存放的值是有类型的。 比如 var foo = 100; foo = 'foo'

动态与静态最大的区别在于编译是发生在执行前还是执行后。

JS是动态类型的

而TypeScript作为静态类型的优势显而易知:

  1. 可读性增强:基于语法解析TSDoc,ide增强。在开发的过程中,在完成一些代码之后,比如一些对象,函数等,可能一两个月之后就会有所遗忘,基于注释可能看得懂,然而仍然难以生成文档,而TS基于语法解析,能够自动生成文档。在实现类型时,相当于写文档。ide能够解析TS的代码,能够得到很强的类型提示。
  2. 可维护性增强:在编译阶段暴露大部分错误。比如常见的语法拼写错误,类型错误,都会及时报错。
  3. 基于这两点,多人合作的大型项目中,获得更好的稳定性和开发效率

TypeScript是JS的超集(superset)

  1. 包含于兼容所有JS特性,支持共存
  2. 支持渐进式引入与升级

最终编译为JS 而且支持各个版本的JS 最低能接受ES3 功能更强大,生态更健全,更完善 vue.js.3.0支持

数据类型

基本数据类型

/* 字符串 */
const q = 'string';     const q:string = 'string';
/* 数字 */
const w = 1;            const w:number = 1;
/* 布尔值 */
const e = true;         const e:boolean = true;
/* null */
const r = null;         const r:null = null;
/* undefined */
const t = undefined;    const t:undefined = undefined

对象类型

/* 对象与接口 */
const bytedancer: IBytedancer ={
    jobId:9303245, 
    name:'Lin', 
    sex:'man', 
    age:28,
    hobby:'swimming',
}
interface IBytedancer {
/* 只读属性:约束属性不可在对象初始化外赋值 */ 
    readonly jobId: number; 
    name:string;
    sex:'man'|'woman'| 'other'; 
    age:number;
/* 可选属性:定义该属性可以不存在 */ 
    hobby?:string;
/* 任意属性:约束所有对象属性都必须是该属性的子类*/
    [key:string]:any;
}

测试只读属性,输入类型,可选属性以及任意属性:

image.png

函数类型

/* 在JS里定义函数 */
function add(x,y) {
    return x+y;
}
const mult = (x,y) => x*y;
​
/* ts里定义 */
interface IMult {
    (x:number, y:number):number;
}
const mult:IMlt = (x,y) => x*y;
​
function add(x:number, y:number): number {
    return x+y;
}
const mult: (x:number, y:number) => number = (x,y) => x*y;

数组类型

/* [类型+方括号]表示 */
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,{},[]];

TypeScript补充类型

分四种类型:1. 空类型 2. 任意类型any 3. 枚举类型 4. 泛型

/* 空类型,表示无赋值 */
type IEmptyFunction = () => void;
/* 任意类型,是所有类型的子类型*/ 
type IAnyType = any;
/* 枚举类型:支持枚举值到枚举名的正、反向映射 */ 
enum EnumExample { 
    add = '+', 
    mult = '*',
}
EnumExample['add'] === '+'; 
EnumExample['+'] ==='add';
enum ECorlor { Mon, Tue, Wed, Thu, Fri, Sat, Sun }; ECorlor['Mon'] === 0; 
ECorlor[0] ==='Mon';
/* 泛型 */
type INumArr = Array<number>;

TypeScript泛型

什么是泛型?

值得注意的是,如果不预先指定具体类型,而在使用的时候再指定类型时怎么处理?我们不预先决定用具体什么类型,而是在使用函数之后才指定,比如跟传入的一致,我们在使用前不知道会传入什么类型的参数,因此也无法预先决定。

比如:

function getRepeatArr(target) {
    return new Array(100).fill(target);
}
//我们想要返回的类型与传入的一致怎么处理?
type IGetRepeatArr = (target:any) => any[];
//然而,以上任意类型显然是有些欠缺的

使用any定义时存在的问题:虽然 以 知道传入值的类型但是无法获取函数返回值的类型;另外也失去了ts类型保护的优势

泛型即是不预先指定具体的类型,使用的时候再指定

泛型的用法
type IGetRepeatArr = <T>(target:T) => T[];
​
/* 泛型接口& 多泛型 */
interface IX<T,U> {
    key: T;
    val: U;
}
/* 泛型类 */
class IMan<T> {
    instance: T;
}
/* 泛型别名 */
type ITypeArr<T> = Array<T>;
泛型约束

泛型约束即是限制泛型必须符合指定的,指定extends后边的对象

/* 以下限制泛型必须符合字符串 */
type IGetRepeatStringArr = <T extends string>(target:T) => T[];
const getStrArr: IGetRepeatStringArr = target => new Array(100).fill(target);

用错误的数字类型测试是否指定类型为字符串生效:

image.png

泛型参数默认类型

泛型参数默认类型即是让泛型没有传参时,默认一个类型。

type IGetRepeatArr<T = number> = (target:T) => T[];
const getRepeatArr: IGetRepeatArr = target => new Array(100).fill(target);

测试:

image.png

字符串/数字 固定值

允许指定字符串/数字必须的固定值

比如:

/* IDomTag必须为html、body、div、span中的其中一个 */
type IDomTag = 'html' | ‘body’ | ‘div’ | ‘span’;
/* IOdd必须为1、3、5、7中的其中一个 */
type IOdd = 1 | 3 | 5 | 7;