日常项目开发使用typescript
共 7593字,需浏览 16分钟
·
2021-06-22 08:00
本文适合日常项目开发使用到TS、以及对TS感兴趣的小伙伴阅读。
欢迎关注前端早茶,与广东靓仔携手共同进阶~
作者:广东靓仔
一、前言
本文基于开源项目:
https://github.com/microsoft/TypeScript
https://www.typescriptlang.org/docs/
二、TS基础知识
Number
,TS指导建议我们不要这样使用。我们都知道在JavaScript代码中几乎从不使用的非原始装箱对象。/* WRONG */
function reverse(s: String): String;
请使用类型数字,字符串和布尔值。
/* OK */
function reverse(s: string): string;
/* OK */
let decLiteral: number = 6;
1、boolean
2、number
3、string
4、[]、Array<>
// 在元素类型后面接上[],表示由此类型元素组成的一个数组
let list: number[] = [1, 2, 3];
// 数组泛型,Array<元素类型>
let list: Array<number> = [1, 2, 3];
5、Tuple
// 声明一个元组
let x: [string, number];
// 正确的初始化
x = ['广东', 10]; // OK
// 错误的初始化
x = [10, '靓仔']; // Error
6、enum
const enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right]
7、any ---- 尽量不使用
8、void
9、undefined和null
10、never
function error(message: string): never {
throw new Error(message);
}
11、类型断言:<>、as
类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构
温馨提示我们定义变量的时候,尽量使用let
三、tsconfig.json 字段说明
tsconfig.json
所包含的属性并不多,只有 7 个。
tsconfig可以到http://json.schemastore.org/tsconfig查看,下面我们重点讲讲字段。
files
: 数组类型,用于表示由 ts 管理的文件的具体文件路径
exclude
: 数组类型,用于表示 ts 排除的文件(2.0 以上支持 Glob)
include
: 数组类型,用于表示 ts 管理的文件(2.0 以上)
compileOnSave
: 布尔类型,用于 IDE 保存时是否生成编译后的文件
extends
: 字符串类型,用于继承 ts 配置,2.1 版本后支持
compilerOptions
: 对象类型,设置编译的选项,不设置则使用默认配置,配置项比较多,后面再列
t
ypeAcquisition
: 对象类型,设置自动引入库类型定义文件(.d.ts
)相关,该对象下面有 3 个子属性分别是:
enable
: 布尔类型,是否开启自动引入库类型定义文件(.d.ts
),默认 false
include
: 数组类型,允许自动引入的库名,如:["jquery", "lodash"]
exculde
: 数组类型,排除的库名
如不设定 files
和 include
,ts 默认是 exclude
以外的所有的以 .ts
和 .tsx
结尾的文件。如果,同时设置 files
的优先级最高,exclude
次之,include
最低。
上面都是文件相关的,编译相关的都是靠 compilerOptions
设置的,接着就来看一看。
属性名 | 值类型 | 默认值 | 描述 |
allowJs | boolean | false | 编译时,允许有 js 文件 |
baseUrl | string | 与 path 一同定义模块查找的路径 | |
declaration | boolean | false | 生成 .d.ts 定义文件 |
jsx | string | "preserve" | jsx 的编译方式 |
noImplicitAny | boolean | false | 不允许隐式
如果false,函数的样子更像js (d)=>{ |
compilerOptions
部分。{
"compilerOptions": {
"allowSyntheticDefaultImports": true, // 允许引入没有默认导出的模块
"module": "es2015",
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"strict": true,
"target": "es5",
"lib": [
"dom",
"es5",
"es2015"
]
}
}
allowSyntheticDefaultImports
是使用 vue 必须的,而设置 module
则是让模块交由 webpack 处理,从而可以使用 webpack2 的摇树。另外,加上allowJs
,这样就可以一点点将现有的 js 代码转换为 ts 代码了。resolve
-> alias
,那么,在 ts config 中也需要通过 baseUrl
+ path
的方式来定义模块查找的方式。<a name="tslint"></a>
四、ts使用小技巧
1.注释
我们平时开发过程可以通过 /** */
形式的注释可以给 TS 类型做标记提示,这样子编辑器会有更好的提示。
/** This is a cool guy. */
interface Person {
/** This is name. */
name: string,
}
const p: Person = {
name: 'cool'
}
当我们鼠标移动到person会有tooltip,一眼就看出来是什么了。
2.接口继承
和类一样,接口也是可以相互继承。让我们能够从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里。
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
一个接口可以继承多个接口,创建出多个接口的合成接口。
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
3interface & type
TypeScript 定义类型的两种方式:接口(interface)和 类型别名(type alias)。
比如下面的 Interface 和 Type alias 的例子中,除了语法,意思是一样的:
Interface
interface Place {
x: number;
y: number;
}
interface SetPlace {
(x: number, y: number): void;
}
Type alias
type Place = {
x: number;
y: number;
};
type SetPlace = (x: number, y: number) => void;
而且两者都可以扩展,但是语法有所不同。此外,请注意,接口和类型别名不是互斥的。接口可以扩展类型别名,反之亦然。
4. typeof
typeof
可以获取一个对象/实例的类型
typeof 只能用在具体的对象上,这与 js 中的 typeof 是一致的,并且它会根据左侧值自动决定应该执行哪种行为。
interface Opt {
timeout: number
}
const defaultOption: Opt = {
timeout: 500
}
有时候可以反过来:
const defaultOption = {
timeout: 500
}
type Opt = typeof defaultOption
5. 运算符
非空断言运算符 !
这个运算符可以用在变量名或者函数名之后,用来强调对应的元素是非 null|undefined 的。
function onClick(callback?: () => void) {
callback!(); // 参数是可选入参,加了这个感叹号!之后,TS编译不报错
}
这个符号的场景,特别适用于我们已经明确知道不会返回空值的场景,从而减少冗余的代码判断,如 React 的 Ref。
function Demo(): JSX.Elememt {
const divRef = useRef<HTMLDivElement>();
useEffect(() => {
divRef.current!.scrollIntoView();
// 当组件Mount后才会触发useEffect,故current一定是有值的
}, []);
return <div ref={divRef}>Demo</div>
}
可选链运算符 ?.
?.
这个是开发者最需要的运行时(当然编译时也有效)的非空判断。
obj?.prop
obj?.[index]
func?.(args)
?.用来判断左侧的表达式是否是 null | undefined,如果是则会停止表达式运行,可以减少我们大量的&&运算。
比如我们写出a?.b
时,编译器会自动生成如下代码
a === null || a === void 0
?
void 0
:
a.b;
这里涉及到一个小知识点:undefined
这个值在非严格模式下会被重新赋值,使用void 0
必定返回真正的 undefined。
空值合并运算符 ??
??与||的功能是相似的,区别在于??在左侧表达式结果为 null 或者 undefined 时,才会返回右侧表达式。
比如我们书写了let b = a ?? 10
,生成的代码如下:
let b = a !== null && a !== void 0
?
a
:
10;
而 || 表达式,大家知道的,则对 false、''、NaN、0 等逻辑空值也会生效,不适于我们做对参数的合并。
数字分隔符_
let num:number = 1_2_345.6_78_9
_可以用来对长数字做任意的分隔,主要设计是为了便于数字的阅读,编译出来的代码是没有下划线的。
五、总结
关注我,一起携手进阶
欢迎关注前端早茶,与广东靓仔携手共同进阶~