原文列举了很多代码中的不好的习惯,在这里我只取一些我可能会犯的错误:

1. Don’t add unneeded context

变量type已经表述的内容不要在其对应的属性中在写一次
Bad: type Car = { carMake: string; carModel: string; carColor: string; }

function print(car: Car): void { console.log(${car.carMake} ${car.carModel} (${car.carColor})); }Good: type Car = { make: string; model: string; color: string; }

function print(car: Car): void { console.log(${car.make} ${car.model} (${car.color})); }

2. Functions should only be one level of abstraction

When you have more than one level of abstraction your function is usually doing too much. Splitting up functions leads to reusability and easier testing.
不要让方法里有多层的抽象,这种情况多数说明你的方法已经做了太多事了,尝试将抽象进行分离。
Bad: function parseCode(code: string) { const REGEXES = [ // ]; const statements = code.split(‘ ‘); const tokens = [];

REGEXES.forEach((regex) => { statements.forEach((statement) => { // … }); });

const ast = []; tokens.forEach((token) => { // lex… });

ast.forEach((node) => { // parse… }); }Good: const REGEXES = [ // ];

function parseCode(code: string) { const tokens = tokenize(code); const syntaxTree = parse(tokens);

syntaxTree.forEach((node) => { // parse… }); }

function tokenize(code: string): Token[] { const statements = code.split(‘ ‘); const tokens: Token[] = [];

REGEXES.forEach((regex) => { statements.forEach((statement) => { tokens.push( // ); }); });

return tokens; }

function parse(tokens: Token[]): SyntaxTree { const syntaxTree: SyntaxTree[] = []; tokens.forEach((token) => { syntaxTree.push( // ); });

return syntaxTree; }这里层数感觉像是forEach的使用次数,一边来说,一个forEach就代表了一种对事件的处理

3. Remove duplicate code

When two implementations from two different modules look similar but live in different domains, duplication might be acceptable and preferred over extracting the common code.
如果只有两段类似的代码段出现在不同的两个组件中,可以不去抽象。

4. Set default objects with Object.assign or destructuring

Bad: type MenuConfig = { title?: string, body?: string, buttonText?: string, cancellable?: boolean };

function createMenu(config: MenuConfig) { config.title = config.title || ‘Foo’; config.body = config.body || ‘Bar’; config.buttonText = config.buttonText || ‘Baz’; config.cancellable = config.cancellable !== undefined ? config.cancellable : true;

// … }

createMenu({ body: ‘Bar’ });Good: type MenuConfig = { title?: string, body?: string, buttonText?: string, cancellable?: boolean };

function createMenu(config: MenuConfig) { const menuConfig = Object.assign({ title: ‘Foo’, body: ‘Bar’, buttonText: ‘Baz’, cancellable: true }, config);

// … }

createMenu({ body: ‘Bar’ });Alternatively, you can use destructuring with default values:
利用解构从结构体中得到参数: type MenuConfig = { title?: string, body?: string, buttonText?: string, cancellable?: boolean };

function createMenu({ title = ‘Foo’, body = ‘Bar’, buttonText = ‘Baz’, cancellable = true }: MenuConfig) { // … }

createMenu({ body: ‘Bar’ });To avoid any side effects and unexpected behavior by passing in explicitly the undefined or null value, you can tell the TypeScript compiler to not allow it. See --strictNullChecks option in TypeScript.
有的时候,可以利用方法的参数的缺省值避免对函数体中参数的是否有值的判断,使代码看起来更清晰整洁。

5. Don’t use flags as function parameters

Flags tell your user that this function does more than one thing. Functions should do one thing. Split out your functions if they are following different code paths based on a boolean.
PS:我经常这么用。。
Bad: function createFile(name: string, temp: boolean) { if (temp) { fs.create(./temp/${name}); } else { fs.create(name); } }Good: function createTempFile(name: string) { createFile(./temp/${name}); }

function createFile(name: string) { fs.create(name); }

6. Favor functional programming over imperative programming

Favor this style of programming when you can.
学会使用reduce和其他的抽象。
PS: 我很少用reduce。。
Bad: const contributions = [ { name: ‘Uncle Bobby’, linesOfCode: 500 }, { name: ‘Suzie Q’, linesOfCode: 1500 }, { name: ‘Jimmy Gosling’, linesOfCode: 150 }, { name: ‘Gracie Hopper’, linesOfCode: 1000 } ];

let totalOutput = 0;

for (let i = 0; i < contributions.length; i++) { totalOutput += contributions[i].linesOfCode; }Good: const contributions = [ { name: ‘Uncle Bobby’, linesOfCode: 500 }, { name: ‘Suzie Q’, linesOfCode: 1500 }, { name: ‘Jimmy Gosling’, linesOfCode: 150 }, { name: ‘Gracie Hopper’, linesOfCode: 1000 } ];

const totalOutput = contributions .reduce((totalLines, output) => totalLines + output.linesOfCode, 0);

7. Avoid negative conditionals

避免反向条件的使用
Bad:
方法用以判定email是否没有用过(很别扭) function isEmailNotUsed(email: string): boolean { // … }

if (isEmailNotUsed(email)) { // … }Good: function isEmailUsed(email): boolean { // … }

if (!isEmailUsed(node)) { // … }

8. Use method chaining

This pattern is very useful and commonly used in many libraries. It allows your code to be expressive, and less verbose. For that reason, use method chaining and take a look at how clean your code will be.
链式调用
Bad: class QueryBuilder { private collection: string; private pageNumber: number = 1; private itemsPerPage: number = 100; private orderByFields: string[] = [];

from(collection: string): void { this.collection = collection; }

page(number: number, itemsPerPage: number = 100): void { this.pageNumber = number; this.itemsPerPage = itemsPerPage; }

orderBy(…fields: string[]): void { this.orderByFields = fields; }

build(): Query { // … } }

// …

const queryBuilder = new QueryBuilder(); queryBuilder.from(‘users’); queryBuilder.page(1, 100); queryBuilder.orderBy(‘firstName’, ‘lastName’);

const query = queryBuilder.build();Good: class QueryBuilder { private collection: string; private pageNumber: number = 1; private itemsPerPage: number = 100; private orderByFields: string[] = [];

from(collection: string): this { this.collection = collection; return this; }

page(number: number, itemsPerPage: number = 100): this { this.pageNumber = number; this.itemsPerPage = itemsPerPage; return this; }

orderBy(…fields: string[]): this { this.orderByFields = fields; return this; }

build(): Query { // … } }

// …

const query = new QueryBuilder() .from(‘users’) .page(1, 100) .orderBy(‘firstName’, ‘lastName’) .build();

9. type vs. interface

Use type when you might need a union or intersection. Use interface when you want extends or implements. There is no strict rule however, use the one that works for you.
For a more detailed explanation refer to this answer about the differences between type and interface in TypeScript.
interface 只能定义对象类型, type 声明的方式可以定义组合类型,交叉类型,原始类型。
如果用 type alias 声明的方式,会导致一些功能的缺失:
interface 方式可以实现接口的 extends 和 implements , 而 type alias 则不行。
interface 可以实现接口的 merge ,但 type alias 则不行。
Bad: interface EmailConfig { // … }

interface DbConfig { // … }

interface Config { // … }

//…

type Shape { // … }Good: type EmailConfig { // … }

type DbConfig { // … }

type Config = EmailConfig | DbConfig;

// …

interface Shape { // … }

class Circle implements Shape { // … }

class Square implements Shape { // … }后续为一些编程原则和测试