typescript使用心得

javascript中的问题

传参错误

const { buy } = require('./buy.js')
const person = {
    name: '张三',
    store: [],
}

const goods = {
    name: '橄榄油',
    unit: '瓶',
    price: 1,
}

buy(person, goods) // 张三买了一瓶橄榄油
// ...
buy(goods, person) // 橄榄油买了一undefined张三
function buy(person, goods) {
    person.store = person.store || []
    person.store.push(goods)
    console.info(`${person.name}买了一${goods.unit}${goods.name}`)
}

exports.buy = buy

buy.js

index.js

javascript

buy.ts

import { Person, Goods } from './types'

function buy(person: Person, goods: Goods): void {
    person.store = person.store || []
    person.store.push(goods)
    console.info(`${person.name}买了一${goods.unit}${goods.name}`)
}

export { buy }

types.ts

interface Person {
    name: string,
    store: any[]
}

interface Goods {
    name: string,
    unit: string,
    price: number
}

export { Person, Goods }

typescript

index.ts

import { Person, Goods } from './types'
import { buy } from './buy'

const person: Person = {
    name: '张三',
    store: [],
}

const goods: Goods = {
    name: '橄榄油',
    unit: '瓶',
    price: 1,
}

buy(person, goods)
// buy(goods, person) 
// Argument of type 'Goods' is not assignable to parameter of type 'Person'.

javascript

17

typescript

30

统计

实现相同功能, 使用代码行数(去除空行, 注释行错误代码)

javascript中的问题

空值问题, 拼写错误

const stuffs = [
    {
        type: 'pm',
        sayHi() {
            console.info(`wang wang wang`)
        },
    },
    {
        type: 'fed',
        sayHi() {
            console.info(`我是前端`)
        },
    },
    {
        type: 'bed',
        sayHi() {
            console.info(`我是后端`)
        },
    },
]

function findStuff(type) {
    return stuffs.find(stuff => stuff.type === type)
}

findStuff('pm').sayHi()
findStuff('hr').sayHi()
// TypeError: Cannot read property 'sayHi' of undefined
findStuff('pm').sayHI()
// TypeError: stuffs.find(...).sayHI is not a function

javascript

interface Stuff {
    type: string
    sayHi: () => void
}

const stuffs: Stuff[] = [
    {
        type: 'pm',
        sayHi(): void {
            console.info(`wang wang wang`)
        },
    },
    {
        type: 'fed',
        sayHi(): void {
            console.info(`我是前端`)
        },
    },
    {
        type: 'bed',
        sayHi(): void {
            console.info(`我是后端`)
        },
    },
]

typescript

// Type 'Stuff | undefined' is not assignable to type 'Stuff'.
// Type 'undefined' is not assignable to type 'Stuff'.
// function findStuff(type: string): Stuff {
//     return stuffs.find((stuff: Stuff) => stuff.type === type)
// }

function findStuff(type: string): Stuff | undefined {
    return stuffs.find((stuff: Stuff) => stuff.type === type)
}

findStuff('pm').sayHi() // Object is possibly 'undefined'

const stuff: Stuff | undefined = findStuff('pm')
if (stuff) {
    stuff.sayHI()
    // Property 'sayHI' does not exist on type 'Stuff'. Did you mean 'sayHi'?
}

"compilerOptions": { "strictNullChecks": true }

统计

typescript - javascript = interface declaration

interface Stuff {
    type: string
    sayHi: () => void
}

javascript中的问题

enum

const Color = {
    RED: 1,
    GREEN: 2,
    BLUE: 3,
}

const shirt = {
    color: Color.RED,
}

console.info(shirt.color) // 1

function foo(color) {
    switch (color) {
        case Color.RED:
            console.info(`the color is red`)
            break
        default:
            console.info(`invalid color`)
    }
}

foo(shirt.color)
foo('red')
foo(6)

javascript

typescript

enum Color {
    RED,
    GREEN,
    BLUE,
}

const shirt: any = {
    color: Color.RED,
}
console.info(shirt.color) // 0

function foo(color: Color): void {
    switch (color) {
        case Color.RED:
            console.info(`the color is red`)
            break
        default:
            console.info(`invalid color`)
    }
}

foo(shirt.color)
foo('red') 
// Argument of type '"red"' is not assignable to parameter of type 'Color'

foo(6) // valid
enum Color {
    RED = 'red',
    GREEN = 'green',
    BLUE = 'blue',
}

const shirt: any = {
    color: Color.RED,
}
console.info(shirt.color) // red

function foo(color: Color): void {
    switch (color) {
        case Color.RED:
            console.info(`the color is red`)
            break
        default:
            console.info(`invalid color`)
    }
}

foo(shirt.color)
foo('red') 
// Argument of type '"red"' is not assignable to parameter of type 'Color'

foo(6) 
// Argument of type '6' is not assignable to parameter of type 'Color'

decorator

更清晰的代码

feedback app.js

typescript无法(不好)解决的问题

ajax获得的数据

request(url, {
    onload(data) {
        if (data.success) {
            const aaa = data.xxx
            aaa.foo() // aaa == null  aaa.foo is not a function
        }
    }
})
interface ResponseData {
    xxx: {
        foo: Function
    }
}

request(url, {
    onload(data: ResponseData) {
        if (data.success) {
            const aaa = data.xxx
            aaa.foo()
        }
    }
})

declaration hell

随着响应中的数据结构越来越复杂, 声明将变得越来越大

结论

1. 不是点石成金, 而是五鬼搬运

        typescript虽然提供了类型检查的便利, 但这是以用户预先定义好变量类型为前提的.

 

 

        比如用户没有做非空判断, 或者拼写的错误, 都会在开发过程中得到IDE的错误提示或在编译过程中得到编译器的报错. 但是保证这一切的前提是用户编写了详细准确的声明文件, 以及在声明变量时写好类型. 各种可能抛错的条件进行判断的工作量依然没有改变, 只是转移了地方.

 

        不过值得高兴的是, 声明文件一般只需要编写一次, 在后续的维护开发中, 这部分工作是很少会大量重复的. 所以抛开声明文件不说, 唯一使ts代码量比js代码量大的地方, 也就只剩声明变量时的 :{type}了

 

        此外, 得益于ts的静态类型特性, 在IDE中用户可以方便的跳转到方法的定义处, 或hover查看方法的参数表甚至doc等, 这是js开发环境难以做到的. 但是这些特性无法在OLOO方式的继承中使用. 

2. 适合代码量大, 结构复杂的项目

3. 对编码仔细, 判空严谨的人, 过多的声明反而成为一种负担

Thank you

deck

By fuucker