TypeScript 入门 | 青训营笔记
这是我参与「第五届青训营 」笔记创作活动的第4天
为什么选择TypeScript
静态类型:
- 可读性强:基于语法解析TSDoc,ide增强
- 可维护性增强:在编译阶段暴露大部分错误,多人合作的大型项目中,获得更好的稳定性和开发效率
JS的超集:
- 包含于兼容所有JS特性,支持共存
- 支持渐进式引入和升级
基本语法
基础数据类型
/* 字符串 */
const q: string = 'string';
/* 数字 */
const w: number = 1;
/* 布尔值 */
const e: boolean = true;
/* null */
const r: null = null;
/* undefined */
const t: undefined = undefined;
对象类型
-
只读属性:约束属性不可在对象初始化外赋值
readonly jobId: number -
可选属性:定义改属性可以不存在
hobby?: string -
任意类型:约束所有对象属性都必须是该属性的子类型
[key : string]: any
函数类型
js函数代码
function add(x, y) {
return x + y;
}
转化为Ts:
- 方法一
interface IAdd { (x:number, y:number): number } const add : IAdd = (x, y) => x + y; - 方法二
function add(x:number, y:number): number { return x + y; } // 箭头函数方式 const add: (x:number, y:number) => number = (x,y) => x + y;
数组类型
补充类型
空类型
// 函数中无返回值
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>
不预先指定具体的类型,而在使用的时候再指定类型
type IGerRepeatArr = <T>(target:T) => T[]
// 数字数组
IGerRepeatArr<Number>
// 字符串数组
IGerRepeatArr<String>
泛型接口 & 多泛型
interface IX<T, U> {
key:T;
val:U;
}
泛型类
class IMan<T> {
instance:T
}
泛型约束
type IGetRepeatStringArr = <T extends string>(target:T) => T[]
const getStrArr : IGetRepeatStringArr = target => new Array(100).fill(target)
/* 报错:类型"number"的参数不能赋给"string"的参数 */
getStrArr(123)
泛型参数默认类型
type IGetRepeatStringArr = <T = number>(target: T) => T[];
const getStrArr: IGetRepeatStringArr = (target) => new Array(100).fill(target);
/* 报错:类型"string"的参数不能赋值给类型"number"的参数 */
getStrArr("123");
类型别名 & 类型断言
通过type关键字定义了IObjArr的类型别名,这样便于使用
type IObjArr = Array<{
key: string;
[objKey: string]: any;
}>
as类型断言
type Record<K extends string | number | symbol, T> = { [P in K]: T; }
function keyBy<T extends IObjArr>(objArr:T) {
const result = objArr.reduce((pre,cur,curIndex) => {
pre[curIndex] = cur;
return pre
},{})
/* 通过as关键字,断言result类型为指定的类型 */
return result as Record<string,T>
}
字符串/数字 字面量
允许指定字符串/数字必须的固定值,即必须为固定值之一
IDomTag必须是html、body、div、span中的其一
type IDomTag = 'html' | 'body' | 'div' | 'span'
高级类型
联合交叉类型
- 联合类型:A | B ;联合类型表示一个值可以是几种类型之一
- 交叉类型:A & B ;多个类型叠加到一起成为一种类型,它包含所需的所有类型的特性
但是如果类型出现了冲突,那么会变成never类型
interface IOne {
author:string
}
interface ITwo {
author:number
}
type Ires = IOne & ITwo
const obj : Ires = {
// 不能将类型“string”分配给类型“never”
author:'123'
}
类型保护与类型守卫
interface IOne {
a:1,
a1:2;
}
interface ITwo {
b:1,
b1:2
}
function log(arg: IOne | ITwo) {
// 类型“IOne | ITwo”上不存在属性“a”。类型“ITwo”上不存在属性“a”。
if(arg.a) {
console.log(arg.a1)
} else {
console.log(arg.b1)
}
}
结论:访问联合类型时,处于程序安全的考虑便,仅能访问联合类型中的交集部分
定义一个类型守卫:
/* 类型守卫:定义一个函数,它的返回值时一个类型谓词,生效范围为子作用域 */
function getIsTOne(arg: IOne | ITwo) : arg is IOne {
// 必须return一个布尔值,用于判断是否是指定类型
return !!(arg as IOne).a
}
function log(arg: IOne | ITwo) {
if(getIsTOne(arg)) {
console.log(arg.a1)
} else {
console.log(arg.b1)
}
}
针对于类型不相同的参数,可以if判断中使用typeof等关键字来区分
function log(arg: string | number) {
if(typeof arg === 'number') {
console.log('number',arg)
} else {
console.log('string',arg)
}
}
联合类型 + 类型保护 = 自动类型推断
function logBook(book:IBookItem) {
if(book.type == 'history') {
console.log(book.range)
} else {
console.log(book.theme)
}
}
Merge 函数类型实现
/**
* 实现merge函数类型
* 要求sourceObj必须是targetObj的子集
* 作用:sourceObj中的值覆盖targetObj中值
*/
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}
}
将其转化为TS版