TypeScrpit的10个错误习惯
1、不使用strict
模式
没有使用strict
模式的tsconfig.json
{
"compilerOptions": {
"target": "ES2015",
"module": "commonjs"
}
}
开启strict
模式:
{
"compilerOptions": {
"target": "ES2015",
"module": "commonjs",
"strict": true
}
}
原因:使得将来修改代码更加容易。
2、使用||
定义默认值
失败通过||
返回可选的值:
function createBlogPost (text: string, author: string, date?: Date) {
return {
text: text,
author: author,
date: date || new Date()
}
}
应当使用新的??
空值合并操作符,或者最好在参数级别定义默认值:
function createBlogPost (text: string, author: string, date: Date = new Date())
return {
text: text,
author: author,
date: date
}
}
原因:当函数特别长时,想要在中间使用并获取到参数的默认值是很难的。
3、使用any
作为类型
当你对数据结构不确定时,使用any
作为数据的类型:
async function loadProducts(): Promise<Product[]> {
const response = await fetch('https://api.mysite.com/products')
const products: any = await response.json()
return products
}
在几乎所有的情况下,你应当用unknown
来代替any
:
async function loadProducts(): Promise<Product[]> {
const response = await fetch('https://api.mysite.com/products')
const products: unknown = await response.json()
return products as Product[]
}
原因:使用any
几乎关闭了ts的类型检查,使得运行时报错很难检查错误。
4、val as SomeType
强制告诉编译器无法推断的类型:
async function loadProducts(): Promise<Product[]> {
const response = await fetch('https://api.mysite.com/products')
const products: unknown = await response.json()
return products as Product[]
}
应当使用is
类型谓词:
function isArrayOfProducts (obj: unknown): obj is Product[] {
return Array.isArray(obj) && obj.every(isProduct)
}
function isProduct (obj: unknown): obj is Product {
return obj != null
&& typeof (obj as Product).id === 'string'
}
async function loadProducts(): Promise<Product[]> {
const response = await fetch('https://api.mysite.com/products')
const products: unknown = await response.json()
if (!isArrayOfProducts(products)) {
throw new TypeError('Received malformed products API response')
}
return products
}
原因:当代码发生变化时,能确保显式的检查而不是强制其类型。
5、测试中使用as any
在测试中创建不完整的数据:
interface User {
id: string
firstName: string
lastName: string
email: string
}
test('createEmailText returns text that greats the user by first name', () => {
const user: User = {
firstName: 'John'
} as any
expect(createEmailText(user)).toContain(user.firstName)
}
测试时使用模拟数据,能够确保重用:
interface User {
id: string
firstName: string
lastName: string
email: string
}
class MockUser implements User {
id = 'id'
firstName = 'John'
lastName = 'Doe'
email = 'john@doe.com'
}
test('createEmailText returns text that greats the user by first name', () => {
const user = new MockUser()
expect(createEmailText(user)).toContain(user.firstName)
}
原因:同上
6、可选属性
属性可有可没有:
interface Product {
id: string
type: 'digital' | 'physical'
weightInKg?: number
sizeInMb?: number
}
建模时应当显式的组合存在或不存在:
interface Product {
id: string
type: 'digital' | 'physical'
}
interface DigitalProduct extends Product {
type: 'digital'
sizeInMb: number
}
interface PhysicalProduct extends Product {
type: 'physical'
weightInKg: number
}
原因:在程序中想要访问不存在的属性,容易报错而且排查困难。
7、一个单词的泛型
泛型的命名为一个单词:
function head<T> (arr: T[]): T | undefined {
return arr[0]
}
建议命名为描述其功能的全名:
function head<Element> (arr: Element[]): Element | undefined {
return arr[0]
}
原因:代码易读,已经后期修改容易。
8、非布尔值的检查
检查一个非布尔值直接通过if
语句:
function createNewMessagesResponse (countOfNewMessages?: number) {
if (countOfNewMessages) {
return `You have ${countOfNewMessages} new messages`
}
return 'Error: Could not retrieve number of new messages'
}
应该显式的条件检查其值:
function createNewMessagesResponse (countOfNewMessages?: number) {
if (countOfNewMessages !== undefined) {
return `You have ${countOfNewMessages} new messages`
}
return 'Error: Could not retrieve number of new messages'
}
原因:当值为0时,容易出现错误。
9、!!
操作符
转换非布尔值到布尔值:
function createNewMessagesResponse (countOfNewMessages?: number) {
if (!!countOfNewMessages) {
return `You have ${countOfNewMessages} new messages`
}
return 'Error: Could not retrieve number of new messages'
}
应该显式的条件检查其值:
function createNewMessagesResponse (countOfNewMessages?: number) {
if (countOfNewMessages !== undefined) {
return `You have ${countOfNewMessages} new messages`
}
return 'Error: Could not retrieve number of new messages'
}
原因:同上。
10、!=null
于!!
类似,!=null
允许同时检测null
和undefined
:
function createNewMessagesResponse (countOfNewMessages?: number) {
if (countOfNewMessages != null) {
return `You have ${countOfNewMessages} new messages`
}
return 'Error: Could not retrieve number of new messages'
}
应该显式的条件检查其值:
function createNewMessagesResponse (countOfNewMessages?: number) {
if (countOfNewMessages !== undefined) {
return `You have ${countOfNewMessages} new messages`
}
return 'Error: Could not retrieve number of new messages'
}
原因:同上。