代码整洁之TypeScript(译)

90 阅读3分钟

本文翻译自medium.com/javascript-…

介绍

上周我写了一篇关于TypeScript中代码气味的文章,这篇文章得到了很多关注和赞誉。所以我认为很多人都想更多地了解代码异味和更具体的 TypeScript。

请记住,代码异味或错误代码并不意味着代码不可用。但作为一名程序员,我认为我们应该生产可重用、可读和可重构的软件。

我不会重复上一篇文章中的错误,如果您还没有阅读,请检查一下

不要添加不必要的上下文

如果你的类/类型/对象名称告诉你一些事情,不要在你的变量名中重复。

避免

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

而应该

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

使用枚举

枚举可以帮助您记录代码的意图。例如,当我们担心值不同而不是这些值的确切值时。

避免

const GENRE = {  
    ROMANTIC: 'romantic',  
    DRAMA: 'drama',  
    COMEDY: 'comedy',  
    DOCUMENTARY: 'documentary',  
}  
  
projector.configureFilm(GENRE.COMEDY);  
  
class Projector {  
    // declaration of Projector  
    configureFilm(genre) {  
        switch (genre) {  
            case GENRE.ROMANTIC:  
            // some logic to be executed  
        }  
    }  
}

应该

enum GENRE {  
    ROMANTIC,  
    DRAMA,  
    COMEDY,  
    DOCUMENTARY,  
}  
  
projector.configureFilm(GENRE.COMEDY);  
  
class Projector {  
    // declaration of Projector  
    configureFilm(genre) {  
        switch (genre) {  
            case GENRE.ROMANTIC:  
            // some logic to be executed  
        }  
    }
}

函数名称应该表明是干啥的

避免

function addToDate(date: Date, month: number): Date {  
// ...  
}  
  
const date = new Date();  
  
// It's hard to tell from the function name what is added  
addToDate(date, 1);

应该

function addMonthToDate(date: Date, month: number): Date {  
// ...  
}  
  
const date = new Date();  
addMonthToDate(date, 1);

更多使用函数式编程而不是指令式编程

避免

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;  
}

应该

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);

避免使用否定式条件

避免

function isEmailNotUsed(email: string): boolean {  
// ...  
}  
  
if (isEmailNotUsed(email)) {  
// ...  
}

应该

function isEmailUsed(email: string): boolean {  
// ...  
}  
  
if (!isEmailUsed(email)) {  
// ...  
}

更多使用不可变性

避免

interface Config {  
host: string;  
port: string;  
db: string;  
}

使用

interface Config {  
readonly host: string;  
readonly port: string;  
readonly db: string;  
}

type vs. interface

当可能需要联合或交集时,请使用type。当您需要扩展或实现时interface,请使用。没有严格的规则,但是,请使用适合您的规则。(没太懂,搜到了这个Typescript 中的 interface 和 type 到底有什么区别

避免

interface EmailConfig {
  // ...
}

interface DbConfig {
  // ...
}

interface Config {
  // ...
}

//...

type Shape = {
  // ...
}

应该

type EmailConfig = {  
// ...  
}  
  
type DbConfig = {  
// ...  
}  
  
type Config = EmailConfig | DbConfig;  
  
// ...  
  
interface Shape {  
// ...  
}  
  
class Circle implements Shape {  
// ...  
}  
  
class Square implements Shape {  
// ...  
}

每个test一个职责

测试也应遵守单一职责原则,一个用例包含一个断言 避免

import { assert } from 'chai';  
  
describe('AwesomeDate', () => {  
it('handles date boundaries', () => {  
let date: AwesomeDate;  
  
date = new AwesomeDate('1/1/2015');  
assert.equal('1/31/2015', date.addDays(30));  
  
date = new AwesomeDate('2/1/2016');  
assert.equal('2/29/2016', date.addDays(28));  
  
date = new AwesomeDate('2/1/2015');  
assert.equal('3/1/2015', date.addDays(28));  
});  
});

应该

import { assert } from 'chai';  
  
describe('AwesomeDate', () => {  
it('handles 30-day months', () => {  
const date = new AwesomeDate('1/1/2015');  
assert.equal('1/31/2015', date.addDays(30));  
});  
  
it('handles leap year', () => {  
const date = new AwesomeDate('2/1/2016');  
assert.equal('2/29/2016', date.addDays(28));  
});  
  
it('handles non-leap year', () => {  
const date = new AwesomeDate('2/1/2015');  
assert.equal('3/1/2015', date.addDays(28));  
});  
});

总结

关于代码整洁有很多话要说,一篇文章是不够的。 但是,如果您想获得更详细的信息,请查看我的参考资料。