这是我参与「第四届青训营 」笔记创作活动的的第12天
👋本文介绍:基本语法(高级类型:联合/交叉类型、类型保护/类型守卫、索引类型keyof、函数返回类型)、工程应用
高级类型
场景1
为书籍列表编写类型
const bookList=[{
author:'xiaoming',
type:'history',
range:'2001-2021',
},{
author:'xiaoli",
type:'story',
theme:'love',
}]
interface IHistoryBook {
author:string;
type:string;
range:string
}
interface IStoryBook {
author:string;
type:string;
theme:string;
}
type IBookList = Array<IHistoryBook | IstoryBook>;
上面存在的问题:类型声明繁琐,存在较多重复
🤔如何改进?
联合/交叉类型
- 联合类型:IA | IB;联合类型表示一个值可以是几种类型之一
- 交叉类型:IA & IB;多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性
type IBookList=Array<{
author:string;
} & ({
type:'history';
range:string;
} | {
type:'story';
theme:string;
})>
场景2
interface IA{a:1,al: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.1og(arg.b1);
}
🤔如何改造?
类型保护与类型守卫
- 类型守卫:定义一个函数,它的返回值是一个类型谓词,生效范围为子作用域
interface IA{a:1,al:2}
interface IB{b:1,b1:2}
/*类型守卫:定义一个函数,它的返回值是一个类型谓词,生效范围为子作用域*/
function getIsIA(arg:IA | IB):arg is IA{
return !!(arg as IA).a;
}
function log2(arg:IA | IB){
if(getIsIA(arg)){
console.log(arg.a1)
}else{
console.log(arg.b1);
}
}
- 类型保护(Type Guards)就是一些表达式,会在运行时检查以确保在某个作用域内的类型。
typeof 类型保护
typeof 类型保护用于判断变量是哪种原始类型。
/*typof 类型保护*/
if(typeof target ==='string'){
return target.split('').reverse().join('');
typeof 类型保护只有两种形式能被识别:
- typeof val === 'typename'
- typeof val !== 'typename'
typename 必须为 number、string、boolean 或 symbol 类型。
但是 TypeScript 并不会阻止与其他字符串比较,语言不会把那些表达式识别为类型保护。
instanceof 类型保护
instanceof 类型保护和 typeof 类型保护用法相似,它主要用于判断是否是一个类的对象或继承对象的。
/*通过instance 类型保护实现对数组的判别*/
if(target instanceof object){
return target.reverse();
instanceof 类型保护是通过构造函数来细化类型,其右侧要求是一个构造函数,TypeScript 将细化为:
- 此构造函数的 prototype 属性的类型,如果它的类型不为 any
- 构造签名所返回类型的联合
案例:自动类型推断
//实现函数logBook类型
//函数接受书本类型,并logger出相关特征
function logBook(book:IBookItem){
//联合类型+类型保护=自动类型推断
if(book.type==='history'){
console.1og(book.range)
}else{
console.1og(book.theme);
}
场景3
实现merge函数类型
要求sourceObj必须为targetObj的子集
//两种实现方式
function mergel(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};
}
//为函数编写类型
interface ISourceObj{
x?:string;
y?:string;
}
interface ITargetobj{
x:string;
y:string
}
type IMerge=(sourceobj:ISourceobj,targetobj:ITargetobj)
=>ITargetobj;
上面存在的问题:
- 类型实现繁琐:若obj类型较为复杂,则声明source和target便需要大量重复2遍
- 容易出错:若target增加/减少key,则需要source联动去除
改进:
索引查询操作符
索引类型的查询操作符 keyof T。
对于任何类型查询操作符,假设 T 是一个类型,那么 keyof T 产生的类型是 T 的属性名称字符串字面量类型构成的联合类型。
interface Person {
name: string;
age: number;
address: string;
}
type person = keyof Person; // 'name' | 'age' | 'address'
keyof Person 是完全可以与 'name' | 'age' | 'address' 互相替换的。
场景4
实现函数delayCall的类型声明205
delayCal接受一个函数作为入参,其实现延迟1s运行函数
其返回promise,结果为入参函数的返回结果
function delaycall(func){
return new Promise(resolve=>{
setTimeout()=>{
const result=func();
resolve(result);
},1000);
});
}
类型声明实现:函数返回值类型
工程应用
浏览器Web | Node.js
Typescript工程应用——Web
以 webpack 为例
- 配置webapack loader相关配置 (把webpack不能识别的文件转化成可以识别的文件,如: ts文件转化为js文件)
- 配置tsconfig.js文件
- 运行wabpack启动,打包
- loader处理ts文件时,会进行编译与类型检查
相关lader
- awesome-typescript-loader:www.npmjs.com/package/awe…
- babel-loader: www.npmjs.com/package/bab…
Typescript工程应用——Node
- 安装Node与npm
- 配置tsconfig.js文件
- 使用npm安装tsc
- 使用tsc运行编译得到js文件
参考文章
- 字节前端青训营PPT
- tsejx.github.io/typescript-…