这是我参与「第四届青训营 」笔记创作活动的第8天
动态类型和静态类型
动态类型语言:在执行期间检查数据的类型的语言。
用这类语言编程,不会给变量指定类型,而是在附值时得到数据类型。
静态类型语言:相反静态类型语言是在执行前编译时检查类型。在写代码时。没声明一个变量必须指定类型。
动态类型语言如JS
return a+b;
}
add(1,2);
add(‘1’,2);
静态类型语言如C++,JAVA等,特点
- 可读性增强:基于语法解析TSDoc,ide增强
- 可维护性增强:在编译阶段暴露出大部分错误=>多人合作的大型项目中获得更好的稳定性和开发效率
return a+b;
}
强类型和弱类型
强类型定义语言:强制数据类型定义的语言。
也就是说,一旦一个变量被指定了某个数据类型,假设不经过强制转换。那么它就永远是这个数据类型了。举个样例:假设你定义了一个整型变量a,那么程序根本不可能将a当作字符串类型处理。
强类型定义语言是类型安全的语言,如Java。
弱类型定义语言:数据类型能够被忽略的语言。它与强类型定义语言相反, 一个变量能够赋不同数据类型的值。如JS。
TypeSc语法
数据类型
- 传统JavaScript(TypeScript可以直接用)
//字符串
const q = 'string';
//数字
const w =1;
//布尔值
const e = true;
//null
const r = null;
//undefined
const t = undefined;
复制代码
- 用TypeScript改进
//字符串
const q: string = 'string';
//数字
const w: number = 1;
//布尔值
const e: boolean =true;
//null
const r: null = null;
//undefined
const t: undefined = undefined;
复制代码
对象类型
const bytedancer: IBytedancer ={
jobId: 12345,
name: 'L',
sex: 'man',
age: 28,
hobby: 'swimming'
}
interface IBytedancer{
//只读属性:约束属性补课在对象初始化外赋值
readonly jobId: number;
name: string;
sex: 'man'|'woman'|'other';
age: number;
//可选属性:定义该属性可以不存在
hobby?: string;
//任意属性,约束所有对象属性都必须是该属性的子类型
//any是ts中特有的类型,就是所有的类型都可以
[key: string]: any;
}
复制代码
函数类型
function add(x,y){
return x+y;
}
const mult = (x,y)=> x*y;
复制代码
上方是一个add函数和一个mult函数,那么如何给其添加类型声明呢
//直接为函数补上参数类型和返回值类型
function add(x: number,y: number): number{
return x+y;
}
//定义一个函数类型,并且把类型赋给变量
const mult: (x:number,y: number)=>number=(x,y)=>x*y;
//通过interface定义类型
interface IMult{
(x: number,y: number): number;
}
//{}内容就是函数类型
const mult: IMult = (x,y) =>x*y;
复制代码
函数重载
//对getDate函数进行重载,timestamp为可缺省参数
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');
const y = getDate('string', '2022-8-5');
//简化代码,通过interface实现以上函数重载
interface IGetDate{
(type: 'string',timestamp?: string): string;
(type: 'date',timestamp?: string): Date;
(type: 'string'|'date',timestamp?: string): Date | string;
}
//报错:不能将类型“(type:any,timestamp:any)=>string|Date”分配给类型"IGetDate"。不能将类型"string|Date"分配给类型"string"。不能将类型"Date"分配给类型"string"。
//类型匹配不上,为了让类型通过,需要让IGetDate的范围大于函数,只需将type:'string'改为any即可
const getDate2: IGetDate = (type, timestamp)=>{
const date = new Date(timestamp);
return type === 'string'?date.toLocaleString() : date;
}
数组类型
//类型+方括号表示
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补充类型
//空类型,表示无赋值
type IEmptyFunction = ()=>void;
//任意类型,是所有类型的子类型
type IAnyType =any;
//枚举类型,支持枚举值到枚举名的正反向映射
enum EnumExample{
add = "+",
mult = "*"
}
EnumExample['add'] === '+';
EnumExample['+'] === 'add';
enum EColor{Mon,Tue,Wed,Thu,Fri,Sat,Sun};
EColor['Mon']===0;
EColor[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>;
复制代码
- 泛型高级用法
//泛型约束,限制泛型必须符合字符串
type IGetRepeatStringArr = <T extends string>(target: T)=>T[];
//报错,number类型的参数不能赋给string类型的参数
const getStrArr: IGetRepeatStringArr = target=>new Array(100).fill(target);
//泛型参数默认类型
type IGetRepeatArr<T = number>=(target: T) =>T[];
//没有传类型,默认number
const getRepeatArr: IGetRepeatArr = target =>new Array(100).fill(target)
//报错,string类型的参数不能赋给number类型的参数
getRepeatArr('123');
复制代码
类型别名&类型断言
//通过type关键字定义了IObjArr的别名类型
type IObjArr = Array<{
key: string;
[objkey: string]: any;
}>
//类型断言
//这里的extends表示T这个类型的数据必须具有IObArr的属性:key和[objkey],多了没关系
function KeyBy<T extends IObjArr>(objArr: Array<T>){
//未指定类型时,result类型是{}
const result = objArr.reduce((res,val,key)=>{
res[key] = val;
return res;
},{});
//通过as关键字,断言result的类型为正确类型
return result as Record<string,T>;
}
字符串/数字 字面量
- 允许执行字符串/数字必须的固定值
//tag必须为html,body,div,span其中一个
type IDomtag = 'html'|'body'|'div'|'span';
//num必须为1,3,5,7,9其中一个
type IDOmnum = 1|3|5|7|9;
高级类型
联合/交叉类型
- 为书籍列表编写类型
const booList= const bookList = [{ author: 'xx', type: 'history', range: '2012-2022', },{ author: 'll', type: 'story', theme: 'love', }]
类型声明繁琐存在重复,type属性实际只能取值history或者story但是这里是string,后面会有隐患
author: string;
type: string;
range: string; }
interface ISroryBook{ author: string;
type: string;
theme: string; }
type IBookList = Array<IHistoryBook | ISroryBook>;
//一个数组,数组内的数据可以是IHistoryBook或者ISroryBook
-
改进类型--联合/交叉类型
- 联合类型: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 log(arg: IA|IB){
//报错,类型“IA|IB”上不存在属性a,类型“IB”上不存在属性a
//类型保护
//访问联合类型时,处于程序安全,仅能访问联合类型中的交集部分
if(arg.a){
console.log(arg.a1)
}else{
console.log(arg.b1)
}
}
//改进,类型守卫,定义一个函数,它的返回值是一个类型谓词,生效范围为子作用域
//类型谓词,返回值通过arg is(函数只能返回布尔值)告诉typescript,当返回值为true,函数类型一定是IA
function getIsIA(arg: IA|IB): arg is IA{
//当存在a的时候断言他一定是IA类型
return !!(arg as IA).a;
}
function log2(arg: IA|IB){
if(getIsIA(arg)){
console.log(arg.a1);
}else{
console.log(arg.b1);
}
}
//实现函数logBook类型
function logBook(book: IBookItem){
//联合类型+类型保护=自动类型推断
if(book.type === 'history'){
console.log(book.range)
}else{
console.log(book.theme);
}
}
一般只有在两个类型完全没有重叠的时候才需要写类型守卫
函数返回值类型
- 实现函数delayCall的类型声明
- delayCall接受一个函数作为入参,实现延迟1s运行函数
- 返回promise,结果为入参函数的返回结果
return new Promise(resolve =>{
setTimeout(()=>{
const result = func();
resolve(result);
}
,1000); });
} //为函数声明类型
type IDelayCall = <T extends()=>any>(
func: T)=>ReturnType<T>;
type IReturnType<T extends (...args: any)
=> any> = T extends (...args:any)=>infer R?R :any
/* T extends(..args:any),此处extends已经不是表示泛型限定,当【extends】关键字跟随泛型出现并且出现在类型的定义中,表示泛型推断,其可表达类比三元表达式,
如 T ===判断类型?类型A:类型B,在这里表示 T是否匹配后面的类型,如果匹配取R类型*/
//关键字【infer】出现在类型推荐中,表示定义类型变量,可以用于指代类型
//如该场景下,将函数的返回值作为变量,使用新泛型R表示,使用在类型推荐命中的结果中