带着目标学习-原文地址:juejin.cn/post/701880…
一、理解ts的学习目标,相比于js完成了哪些功能,有哪些优势?
对比js
TS是JS的超集,兼容js语法,顾名思义解决js(动态类型)变量类型不确定带来的问题,编译时就发现错误,而不是运行时才报错
TS不能被js解析器解析,需要编译(类似于高版本js编译为低版本js才能被浏览器的js解析器解析)
类比于less、sass之于css
最终需要编译为js,但扩展了原有特性
新特性
扩展了类型 inteface
添加es不具有的新特性 装饰器、接口
丰富的配置选项(严格程度,编译为任意版本的js)
强大的开发工具
优势
学习成本低
减少团队无效沟通
让代码更健壮
二、ts环境搭建
环境搭建(全局安装ts及编译器)
npm i -g typescript ts-node
在工程中创建ts配置文件
ts-node --init
创建ts文件-index.ts
执行该ts文件内容
ts-node index.ts
在线ts练习地址:www.typescriptlang.org/zh/play
三、语法
基础语法-关注类型
对标js的内置类型
let string1: string = "jimmy";
let number1: number = 88;
let boolean1: boolean = false;
let undefined1: undefined= undefined;
let null1: null= null;
let obj1: object = {x: 1};
let bigint1 :bigint = BigInt(100);
let symbol1: symbol = Symbol("hello");
特殊地,默认情况下null和undefined为所有类型的子类型,可以把作为其他类型的值,但tsconfig.json若配置strictNullChecks为true则null和undefined只能赋值给自身类型和void
tips:number和bigint不兼容
typescript中的any编译器开启noImplicitAny,则js写法(不设置类型,等同于设置类型为any)则会引起报错-不允许为any类型
void无任何类型,常用语函数无返回值时设置返回值类型(可被赋予null、undefined但无意义)
never类型,用于检测死循环或者抛出异常
let nev: never = (()=>{while(true)} ()) 死循环、throw异常 才支持被赋值
联合类型
设置数据多个类型,以数组定义为例:
let arr: (string | number)[] = [ '1,', 2, '3', 4 ]
let arr1: Array<string | object> = [ 1, '1', { name: 'gpf' } , '2' ]
要点:支持自定义类型
let arrCustom: Array<string | object| customObj> = [1, '1', {name: 'gpf'}, '2']
类型定义-普通类型
let arr: string[] = [ '1,','3' ]
强类型约束,类型不同的报错:
let arr: Array<string | object>[] = ['1,',3]
- error TS2322: Type 'number' is not assignable to type 'string | object'.
类型定义-函数声明(可选参数、默认值、特殊写法、收集参数)
function fun1(params1: string, params2: customerObj, params3?: 可选参数): string[] {
let ret: string[] = []
...
return ret
}
支持函数重载,不同类型、数量、顺序的同名函数为重载
类型定义-js扩展类型-元组(设置一个形似数组的固定类型集合)
可选参数、默认值、特殊写法、收集参数--同函数
只读元组
类型推断-简写方法
很多场景ts会根据上下文自动推断变量类型,const声明的变量例外
/** 根据参数的类型,推断出返回值的类型也是 number /functionadd1(a: number, b: number) { returna + b; } constx1= add1(1, 1); // 推断出 x1 的类型也是 number/* 推断参数 b 的类型是数字或者 undefined,返回值的类型也是数字 */functionadd2(a: number, b = 1) { returna + b; } constx2 = add2(1); constx3 = add2(1, '1'); // ts(2345) Argument of type "1" is not assignable to parameter of type 'number | undefined
声明时没赋值,则被推断为any
类型推断-类型断言
以下greaterThan2执行结果获得number或者undefined,会报ts2322,可采用断言方式可进行强转--as number
const arrayNumber: number[] = [1, 2, 3, 4];
const greaterThan2: number = arrayNumber.find(num=> num > 2) as number;
非空断言
let mayNullOrUndefinedOrString: null | undefined | string; mayNullOrUndefinedOrString!.toString(); // ok
字面量类型-类似于枚举或者字典,该类型的数据只能取该范围的数据
let obj: 'hello' | 'body' | 'eee'
obj = 'err'
obj = 'hello'
常用形式
interface Config {
size: 'small' | 'big';
isEnable: true | false;
margin: 0 | 2 | 4;
}
推断造成并不能精确确定类型,此时产生对类型的拓宽与缩小,便于灵活调控类型推断
类型推断-类型拓宽
let yy = 'string'
此时yy被推断为string类型,而不是字面量类型('string', null, undefined, any),因此完全借助类型推断是不行的,必要的地方还必须设置
类型推断-类型缩小
结合类型判断
type&interface
设置类型别名
type myType1 = string | string[]
function fun(str: myType1): void{}
交叉类型:将类型合并处理
type myTYpe2 = number & string
type IntersectionType= { id: number; name: string; } & { age: number }; constmixed: IntersectionType= { id: 1, name: 'name', age: 18}配合接口实现多接口继承效果
考虑多接口字段名相同 问题--字段类型不兼容(一个strinng、一个 number报错)、若是对象类型,则可以合并
interface
interface Person {
name: string; // 必选属性
age?: number; // 可选属性
[propName: string]: any; //任意属性(属性名任意)
}
约束:其中必备属性必须被设置
开放:可以设置可选属性
开放:可以设置任意属性,但类型要包含必选属性和可选属性
泛型,待进一步研究
ts.config.js
ts的编译配置选项
-
files - 设置要编译的文件的名称;
-
include - 设置需要进行编译的文件,支持路径模式匹配;
-
exclude - 设置无需进行编译的文件,支持路径模式匹配;
-
compilerOptions - 设置与编译流程相关的选项。
{ "compilerOptions": { /* 基本选项 */ "target": "es5", // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT' "module": "commonjs", // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015' "lib": [], // 指定要包含在编译中的库文件 "allowJs": true, // 允许编译 javascript 文件 "checkJs": true, // 报告 javascript 文件中的错误 "jsx": "preserve", // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react' "declaration": true, // 生成相应的 '.d.ts' 文件 "sourceMap": true, // 生成相应的 '.map' 文件 "outFile": "./", // 将输出文件合并为一个文件 "outDir": "./", // 指定输出目录 "rootDir": "./", // 用来控制输出目录结构 --outDir. "removeComments": true, // 删除编译后的所有的注释 "noEmit": true, // 不生成输出文件 "importHelpers": true, // 从 tslib 导入辅助工具函数 "isolatedModules": true, // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).
/* 严格的类型检查选项 */ "strict": true, // 启用所有严格类型检查选项 "noImplicitAny": true, // 在表达式和声明上有隐含的 any类型时报错 "strictNullChecks": true, // 启用严格的 null 检查 "noImplicitThis": true, // 当 this 表达式值为 any 类型的时候,生成一个错误 "alwaysStrict": true, // 以严格模式检查每个模块,并在每个文件里加入 'use strict'
/* 额外的检查 */ "noUnusedLocals": true, // 有未使用的变量时,抛出错误 "noUnusedParameters": true, // 有未使用的参数时,抛出错误 "noImplicitReturns": true, // 并不是所有函数里的代码都有返回值时,抛出错误 "noFallthroughCasesInSwitch": true, // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)
/* 模块解析选项 */ "moduleResolution": "node", // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6) "baseUrl": "./", // 用于解析非相对模块名称的基目录 "paths": {}, // 模块名到基于 baseUrl 的路径映射的列表 "rootDirs": [], // 根文件夹列表,其组合内容表示项目运行时的结构内容 "typeRoots": [], // 包含类型声明的文件列表 "types": [], // 需要包含的类型声明文件名列表 "allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入。
/* Source Map Options */ "sourceRoot": "./", // 指定调试器应该找到 TypeScript 文件而不是源文件的位置 "mapRoot": "./", // 指定调试器应该找到映射文件而不是生成文件的位置 "inlineSourceMap": true, // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件 "inlineSources": true, // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性
/* 其他选项 */ "experimentalDecorators": true, // 启用装饰器 "emitDecoratorMetadata": true // 为装饰器提供元数据的支持 } }