TS 基础
背景
-
强类型 vs 弱类型 :
类型安全,更强的类型约束。 强类型不允许任意隐式类型转换,弱类型允许任意类型转换。
-
静态类型语言 vs 动态类型语言:
类型检查的时机不同。静态类型在编译阶段就确定每个变量的类型,而动态类型在运行阶段才确定每个变量的类型。
JS:动态类型语言,弱类型。 被设计时,小规模脚本,且不需要编译。TS 也是弱类型,不会修改 JS 运行时的特性。
强类型:错误更早暴露。代码更智能。重构更牢靠。
TS 特性
- 类型系统是核心特性。类型安全,定义了类型后的方法提示。
- 静态类型的弱类型。
Flow
JS 的类型检查工具
JS 的类型检查,是一个小工具,在需要的时候添加类型,学习成本较小。
-
使用方式
yarn add flow-bin
yarn flow init
yarn flow
工具推荐: vscode 插件 Flow Language Support
-
移除类型注解
-
yarn add flow-remove-types
yarn flow-remove-types . -d dist
//转换到某个目录下 -
yarn add @babel/core @babel/cli @babel/preset-flow --dev
{"presets":["@babel/preset/preset-flow"]}
//.babelrcyarn babel src -d dist
-
类型推断:如果未添加类型注解,则自动推断类型的特性,但尽可能还是添加类型注解。
思路:编写的代码和实际运行的代码分开,添加了编译的环节。
// @flow 加在开头使用flow检测类型.也可用 /* @flow */
function sum(a: number, b: number) {
//类型注解
return a + b;
}
function foo(): void {
//返回值的注解
//类型注解:函数返回值为空
//no return
}
//标识数组类型
//由数字组成的数组
const arr1: Array<number> = [1, 2, 3];
const arr2: number[] = [1, 2, 3];
//元组:固定长度,固定类型的数组
const foo: [string, number] = ["foo", 1];
//标识对象类型
const obj1: { foo: string, bar: number } = { foo: "string", bar: 1 }; //至少有foo,bar这两个成员
const obj2: { foo?: string, bar: number } = { foo: "string", bar: 1 }; //添加?表示可选的
const obj3: { [string]: string } = {}; //k限制key和值的类型,不限制key的个数
//标识函数类型
function foo(callback: (string, number) => void) {
//回调函数的参数以及返回值的类型注解
callback("string", 1);
}
//特殊类型
const a: "foo" = "foo"; //字面量类型,只能是'foo'
const type: "success" | "warning" | "danger" = "success"; //联合类型,只能是其中之一
const b: string|number //string 或者字符串
const StringOrNumber = string | number //给类型定义别名,可复用了
const b: StringOrNumber
const gender:?number = null //加?则可以使用null/undefined
const gender: number | null | undefined //与上面一致
//mixed any 所有类型都可
//mixed :强类型,不能隐式类型转换
//any :不限制,可以隐式类型转换,可以兼容老代码,一般不要使用
function passMixed (value:mixed){
//...
}
function passMixed (value:any){
//...
}
更多类型查询: https://www.saltycrane.com/cheat-sheets/flow-type/latest/
tsc 命令
.ts
文件不能直接在 node/浏览器环境中执行,需要先编译为 js 文件。如果希望在 node 环境直接运行 ts ,可以使用ts-node
包 ,全局安装后,命令行使用ts-node hello.ts
。
tsc hello.ts
以上命令可以编译 hello.ts
文件到 js,会在同一个目录下生成同名 js 文件。
tsc xx -w
watch mode ,内容改变则重新编译。
yarn tsc --init
生成tsconfig.json
tsc
直接运行,使用 tsconfig.json
配置文件,会编译当前目录所有 ts 文件。
{
"include": [ //包含的文件
"**/*.ts"
],
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"declaration": true,
"outDir": "./dist",
"rootDir": "./src",
"lib": [
"es2015",
"dom",
"es2016",
"es2017",
"esnext"
],
"types": [
"node"
]
}
}
TypeScript: Documentation - What is a tsconfig.json
yarn tsc --local zh-CN
中文错误消息。
TypeScript 只会在编译时对类型进行静态检查,如果发现有错误,编译的时候就会报错。而在运行时,与普通的 JavaScript 文件一样,不会对类型进行检查。
TypeScript 编译的时候即使报错了,还是会生成编译结果,我们仍然可以使用这个编译之后的文件。
如果要在报错的时候终止 js 文件的生成,可以在 tsconfig.json 中配置 noEmitOnError
tsup
另一个 ts 的构建工具,基于 esBuild,打包速度快,可以生成多个支持不同模块规范的包。
安装之后默认不需要配置即可使用。也可以配置入口文件、打包类型、是否生成类型文件等。
类型声明
没有类型声明文件的库,可以自己写类型声明对全局文件进行类型定义。
declare function replace(input: string): string; //如果没有类型声明,自己声明一下类型。
declare function replace(input: number): number; //可以相同的函数名字,参数不同,函数重载
// 命名空间的嵌套
declare namespace $$ {
namespace hh {
function getName(): string;
}
namespace fn {
class init {}
}
}
//声明模块
declare module 'xx' {
export function getName(): string;
}
有类型声明的库,如果声明缺失内容不符合当前业务场景,可以扩展类型声明文件,实现类型融合的特性。
declare module Express {
export interface Request {
user: {
name: string;
};
}
}
- 使用第三方库的 TS 支持问题
很多第三方库原生支持 TS,在使用时就能获得代码补全和提示。
而有些第三方库原生不支持 TS, 可以安装社区维护的类型声明库来获得代码补全的能 力。比如使用npm install --save-dev @types/react
安装 React 的类型声明库。
DefinitelyTyped 组织的类型定义,包含大多数流行的包的类型定义:DefinitelyTyped: The repository for high quality TypeScript type definitions.,他们的包名是@types/pkgName
。
类似 node 包查找顺序的递归查找
-
局部作用域:当前文件
-
项目类型声明文件:
*.d.ts
-
node_modules/@types
可以通过 tsconfig.json 中 typeRoot 指定类型声明文件位置,默认为@types,会引入所有的类型声明。
可以通过 compilerOptions.types 配置 控制需要引入哪些包的类型声明,以避免全局变量污染的问题。