“这是我参与「第五届青训营 」笔记创作活动的第4天”
可以参考的学习资料
练习的地方
TS基本语法
/* 字符串 */
const q: string = 'string';
/* 数字 */
const q: number = 0;
/* 布尔值 */
const q: boolean = true;
/* null */
const q: null = null;
/* 字符串 */
const q: undefined = undefined;
复制代码
对基础数据类型来说,我们一般需要给它限制具体的数据类型,这是TS的规范之一。
对象类型
- 可以自己创建一个自己想要的格式「类型」
const bytedancer: IBytedancer = {
jobId: 9303245,
name: 'Lin',
sex: 'man',
age: 28,
hobby: 'swimming',
}
复制代码
一般这个
IBytedancer前面有一个I,表示它是我们自定义得出的。
还可以这样定义「使用interface」
interface IBytedancer {
readonly jobId: number;
name: string;
sex: 'man'|'woman'|'other';
age: number;
hobby?: string;
[key: string]: any;
}
复制代码
- 其中
readonly表示这是一个只读属性,如果你后续想要去修改他,会得到报错。- 其中
?表示这是一个可选属性,也就是定义该属性可以不存在- 其中
:any表示这是一个任意属性,约束所有对象属性都必须是该属性的子类型
函数类型
- 之前的
JS
function add(x, y) {
return x + y
}
const mult = (x, y) => x * y
复制代码
- 现在的
TS
function add(x: number, y: number): number {
return x + y;
}
复制代码
给基础数据类型做了一些限制,还有给函数的返回值做了一些限制
const mult: (x: number, y: number) => number = (x, y) => x * y
复制代码
函数重载
function getDate(type: 'string', timestamp?: string): string;
interface IGetDate {
(type: 'string', timestamp?: string): string;
(type: 'date', timestamp?: string): Date;
(type: 'string'|'date',timestamp?:string): Date | string;
}
复制代码
数组类型
- 「类型 + 方括号」表示
type IArr1 = number[];
复制代码
- 泛型表示
type IArr2 = Array<string | number | Record<string, number>>;
复制代码
- 元组表示
type IArr3 = [number, number, string, string]
复制代码
- 接口表示
interface IArr4 {
[key: number]: any;
}
复制代码
Typescript补充类型
- 空类型,表示无赋值
type IEmptyFunction = () => void;
复制代码
- 任意类型,是所有类型的子类型
type IAnyType = any;
复制代码
- 枚举类型:支持枚举值到枚举名的正,反向映射「仅有数字可以|字符串不行」
enum EnumExample { Mon, Tue, Wed, Thu, Fri, Sat, Sun }
EnumExample['Mon'] === 0
EnumExample[0] = 'Mon'
复制代码
- 泛型
type INumArr = Array<number>;
复制代码
Typescript泛型
function getRepeatArr(target) {
return new Array(100).fill(target);
}
type IGetRepeatArr = (target: any) => any[];
复制代码
- 不预先指定具体的类型,而在使用的时候再指定类型的一种特性
type IGetRepeatArrR = <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)
getStrArr(123) // 会报错!!!因为是number类型的数据
复制代码
类型别名 & 类型断言
- 通过
type关键字定义了IObjArr的别名。
type IObjArr = Array<{
key: string;
[objKey: string]: any;
}>
复制代码
functiom keyBu<T extends IObjArr>(objArr: Array<T>) {
const result = objArr.reduce((res, val, key) => {
res[key] = val;
return res;
}, {});
return result as Record<string, T>;
}
复制代码
- 还可以直接用字面量来定义类型
type IDomTag = 'html' | 'body' | 'div' | 'span'
type IOddNumber = 1 | 2 | 3 | 4 | 5 | 7 | 9
复制代码
联合/交叉类型
- 联合类型:
IA|IB;联合类型表示一个值可以是几种类型之一 - 交叉类型:
IA&IB;多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性
type IBookList = Array<{
author: string;
} & ({
type: 'history';
range: string;
} | {
type: 'story';
theme: string
})>
复制代码
类型保护与类型守卫
interface IA {a: 1, a1: 2}
interface IB {b: 1, b1: 2}
function log2(arg: IA | IB) {
// 这里是会报错的,如果说存在问题的话
if(arg.a) {
console.log(arg.a1)
} else {
console.log(arg.b1)
}
}
复制代码
- 类型守卫:定义一个函数,它的返回值是一个类型谓词,生效范围为子作用域
function getIsIA(arg: IA | IB): arg is IA {
return !!(arg as IA).a;
}
// 再来判断是IA还是IB就不会出问题了
function log3(arg: IA | IB) {
if (getIsIA(arg)) {
console.log(arg.a1)
} else {
console.log(arg.b1)
}
}
复制代码
高级类型
/**
* 实现merge函数类型
* 要求sourceObj必须为targetObj的子集
*/
function merge1(sourceObj, targetObj) {
// 扩展运算符拿出来这些东西
const result = { ...sourceObj };
for(let key in targetObj) {
const itemVal = sourceObj[key];
// 就是替换原本有的东西
itemVal && (result[key] = itemVal);
}
return result;
}
// Question 不太懂这样做了有啥意义
function merge2(sourceObj, targetObj) {
return { ...sourceObj, ...targetObj };
}
复制代码
- 类型实现频繁:若obj类型较为复杂,则声明source和target便需要大量重复2遍
- 容易出错:若target增加/减少key,则需要source联动去除
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;
}
type IPartial<T extends Record<string, any>> = {
[P in keyof T]?: T[P];
}
type IKeys = keyof {a: string; b: number} // => type IKeys = "a" | "b"