TS规范
基本规范
命名,声明
- 使用PascalCase命名类,枚举,接口,组件名
- 使用camelCase命名函数名,属性,本地变量名
- 勿将C#的规范套用到TS中
- 类型定义需在文件顶部声明
- 文件名中使用小写
-来分隔多个单词,例如home-api - 基本类型使用string,number等而非String,Number这类的装箱类型
- 充分使用泛型和类型运算避免多余类型标记
- 减少或者规避any的滥用,any等于放弃了类型检测,等于掩盖了类型设计
- 推荐使用扩展性更强的interface,接口创建一个单一的平面对象类型来检测属性冲突,交叉类型是递归进行合并
- 保持一种扩展形式,不要或减少interface和type互相扩展的混用情况
- 避免使用Object来包裹其他类(String,Number等)
- 优先使用类型声明而非类型断言
- 使用Index Signature来表示动态数据,并尽可能细化来表示类型安全
- 优先使用Arrays,Tuple,ArrayLike而非number index signatures
类
- 成员顺序按照 静态>实例,属性>方法,公开>保护>私有
- 始终定义修饰符
- 避免使用TS构造函数来定义属性
- 使用Error相关类表示异常
模块
- import顺序按照 npm模块,自我编写模块,相对路径,每组用空格进行分隔
- 若类型被多个模块共享,则提取到types.ts中,全局类型,变量统一写在global.d.ts中
- 避免使用require导致TS检查被绕过
- 一个模块进定义一个类,文件名需和类名相同
函数
- 若无需返回值,返回类型声明为void*,而非any**
- 若函数参数类型变化多样,尝试使用可选参数,联合类型来表示参数类型,避免定义多个函数重载
- 使用箭头函数绑定上下文;使用箭头函数代替匿名函数表达式
- 回调函数请勿包含可选参数
- 为回调函数提供this的类型
- 使用typeof fn来标注增强的函数类型
- 使用async/await来取代Promise
- 使用undefined,而非null
Interface && Type 对比
- 两者十分相似,大部分情况下可以混用,关键区别是type不可以被重新打开并增加新属性,而interface总是可以拓展
- 官方推荐总是优先使用interface
- 如果定义原始基础类型的别名,使用type
- 如果定义函数类型,联合类型,使用type
- 对于所有object的类型,使用interface,并且interface更方便做声明合并
其他
- 注释代码使用TSDoc进行规范
- 应和其他强类型语言一样,假设 Array 是不可变数据结构(Immutable)
- 总是使用
{}来包裹循环体和条件语句 - 使用对象展开,数组展开来取代Object.assign和Array.prototype.concat
- 使用readonly来避免mutation造成的错误
- 要一直致力于减少null和undefined的影响范围
- 优先使用union of interface而不是interfaces of unions
- 优先使用unknown而非any
- private在运行时并不能阻止外部用户的访问
TSLint
TSLint官网,建议在项目中添加TSLint来进一步约束规范,配置文件中的核心项目有以下:
extends?: string | string[]预设配置的文件名称,也可以是配置文件的引用路径rulesDirectory?: string | string[]自定义规则的目录路径,可以用一个数据来描述多个路径rules?: { [name: string]: RuleSetting }规则的详细配置映射defaultSeverity?: "error" | "warning" | "off"严重程度设置
小Tips
- 使用type-converage去测试type的覆盖率
- 将@types的依赖放置在devDependencies中
- 使用TSDOC去注释导出的函数,class,types
在 Vue 中使用 TS
在 React 中使用 TS
安装
npm i -D @types/react @types/react-dom @types/react-redux
"react" - `@types/react`
"react-dom" - `@types/react-dom`
"redux" - (types included with npm package)*
"react-redux" - `@types/react-redux`
React 类型表
React.FC<Props> | React.FunctionComponent<Props>
方法组件
const MyComponent: React.FC<Props> = ...
React.Component<Props, State>
类组件
class MyComponent extends React.Component<Props, State> { ...
React.ComponentType<Props>
方法组建 类组件 联合类型
const withState = <P extends WrappedComponentProps>(
WrappedComponent: React.ComponentType<P>,
) => { ...
React.ComponentProps<typeof XXX>
获取指定组件的Props类型
type MyComponentProps = React.ComponentProps<typeof MyComponent>;
React.ReactElement | JSX.Element
Reac基本元素类型,表示了原始Dom元素
const elementOnly: React.ReactElement = <div /> || <MyComponent />;
React.ReactNode
任何可能的React节点类型
const elementOrPrimitive: React.ReactNode = 'string' || 0 || false || null || undefined || <div /> || <MyComponent />;
const Component = ({ children: React.ReactNode }) => ...
React.CSSProperties
JXS中的样式对象类型(用于行内样式)
const styles: React.CSSProperties = { flexDirection: 'row', ...
const element = <div style={styles} ...
React.XXXHTMLAttributes<HTMLXXXElement>
指定HTML元素的HTML属性类型
const Input: React.FC<Props & React.InputHTMLAttributes<HTMLInputElement>> = props => { ... }
<Input about={...} accept={...} alt={...} ... />
React.ReactEventHandler<HTMLXXXElement>
范型通用事件处理类型
const handleChange: React.ReactEventHandler<HTMLInputElement> = (ev) => { ... }
<input onChange={handleChange} ... />
React.XXXEvent<HTMLXXXElement>
表示了更多的指定事件类型, 一些常见的有: ChangeEvent, FormEvent, FocusEvent, KeyboardEvent, MouseEvent, DragEvent, PointerEvent, WheelEvent, TouchEvent.
const handleChange = (ev: React.MouseEvent<HTMLDivElement>) => { ... }
<div onMouseMove={handleChange} ... />
代码示例
Function组件
import * as React from 'react';
type Props = {
label: string;
count: number;
onIncrement: () => void;
};
export const FCCounter: React.FC<Props> = props => {
const { label, count, onIncrement } = props;
const handleIncrement = () => {
onIncrement();
};
return (
<div>
<span>
{label}: {count}
</span>
<button type="button" onClick={handleIncrement}>
{`Increment`}
</button>
</div>
);
};
Class组件示例
import * as React from 'react';
type Props = {
label: string;
};
type State = {
count: number;
};
export class ClassCounter extends React.Component<Props, State> {
readonly state: State = {
count: 0,
};
handleIncrement = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
const { handleIncrement } = this;
const { label } = this.props;
const { count } = this.state;
return (
<div>
<span>
{label}: {count}
</span>
<button type="button" onClick={handleIncrement}>
{`Increment`}
</button>
</div>
);
}
}
tsconfig示例
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true, /* allows javaScript files to be compiled */
"skipLibCheck": true, /* skip type checking of all declaration files */
"esModuleInterop": true, /* disables namespace imports (import * as fs from "fs") and enables CJS/AMD/UMD style imports (import fs from "fs") */
"allowSyntheticDefaultImports": true, /* allows default imports from modules with no default export */
"strict": true, /* enables all strict type checking options */
"module": "esnext", /* specifies module code generation */
"moduleResolution": "node", /* resolves modules using Node engine */
"isolatedModules": true, /* unconditionally emits imports for unresolved files */
"resolveJsonModule": true, /* includes modules imported with .json extension */
"noEmit": true, /* Not to compile code, only performs type checking */
"jsx": "react", /* Support JSX in .tsx files (This one comes in handy sometimes) */
"sourceMap": true, /* generates corrresponding .map file */
"declaration": true, /* generate corresponding .d.ts file */
"noUnusedLocals": true, /* reports errors on unused locals (suggested for clean code writing) */
"noUnusedParameters": true, /* report errors on unused parameters (again, suggested for clean code writing) */
},
"include": [
"src/**/*" // *** The files TypeScript should type check ***
],
"exclude": ["node_modules", "build"] // *** The files to not type check ***
}
相关链接
**