Heim > Artikel > Web-Frontend > 10 schlechte Gewohnheiten, die Sie beim Schreiben von Code in TypeScript ablegen sollten
TypeScript und JavaScript haben sich in den letzten Jahren stetig weiterentwickelt. Wir haben in der Vergangenheit beim Schreiben von Code einige Gewohnheiten entwickelt, von denen einige wenig Sinn ergeben. Hier sind 10 schlechte Gewohnheiten, die wir alle ablegen sollten.
strikten
-Modus nicht verwendenstrict
模式没有用严格模式编写 tsconfig.json
。
{ "compilerOptions": { "target": "ES2015", "module": "commonjs" } }
只需启用 strict
模式即可:
{ "compilerOptions": { "target": "ES2015", "module": "commonjs", "strict": true } }
在现有代码库中引入更严格的规则需要花费时间。
更严格的规则使将来维护代码时更加容易,使你节省大量的时间。
||
定义默认值使用旧的 ||
处理后备的默认值:
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 } }
??
运算符是去年才引入的,当在长函数中使用值时,可能很难将其设置为参数默认值。
??
与 ||
不同,??
仅针对 null
或 undefined
,并不适用于所有虚值。
any
类型当你不确定结构时,可以用 any
类型。
async function loadProducts(): Promise<Product[]> { const response = await fetch('https://api.mysite.com/products') const products: any = await response.json() return products }
把你代码中任何一个使用 any
的地方都改为 unknown
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
是很方便的,因为它基本上禁用了所有的类型检查。通常,甚至在官方提供的类型中都使用了 any
。例如,TypeScript 团队将上面例子中的 response.json()
的类型设置为 Promise 2cfd83bcbfaff9bacc12c0937fd77054
。
它基本上禁用所有类型检查。任何通过 any
进来的东西将完全放弃所有类型检查。这将会使错误很难被捕获到。
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[] }
这正是 Type Guard
的用武之地。
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 }
从 JavaScript 转到 TypeScript 时,现有的代码库通常会对 TypeScript 编译器无法自动推断出的类型进行假设。在这时,通过 as SomeOtherType
可以加快转换速度,而不必修改 tsconfig
中的设置。
Type Guard
会确保所有检查都是明确的。
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) }
在给尚不具备广泛测试覆盖条件的代码编写测试时,通常会存在复杂的大数据结构,但要测试的特定功能仅需要其中的一部分。短期内不必关心其他属性。
在某些情况下,被测代码依赖于我们之前认为不重要的属性,然后需要更新针对该功能的所有测试。
将属性标记为可选属性,即便这些属性有时不存在。
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 }
将属性标记为可选而不是拆分类型更容易,并且产生的代码更少。它还需要对正在构建的产品有更深入的了解,并且如果对产品的设计有所修改,可能会限制代码的使用。
类型系统的最大好处是可以用编译时检查代替运行时检查。通过更显式的类型,能够对可能不被注意的错误进行编译时检查,例如确保每个 DigitalProduct
都有一个 sizeInMb
Wie sieht diese Gewohnheit aus
tsconfig.json
. 🎜function head<T> (arr: T[]): T | undefined { return arr[0] }
strikten
-Modus: 🎜function head<Element> (arr: Element[]): Element | undefined { return arr[0] }
||
, um Standardwerte zu definieren||
verarbeitet den Standardwert des Fallbacks: 🎜function createNewMessagesResponse (countOfNewMessages?: number) { if (countOfNewMessages) { return `You have ${countOfNewMessages} new messages` } return 'Error: Could not retrieve number of new messages' }
??
-Operator verwenden, oder in Parameter Standardwerte neu definieren. 🎜function createNewMessagesResponse (countOfNewMessages?: number) { if (countOfNewMessages !== undefined) { return `You have ${countOfNewMessages} new messages` } return 'Error: Could not retrieve number of new messages' }
??
Der Operator wurde erst letztes Jahr eingeführt, und bei der Verwendung von Werten in langen Funktionen ist dies der Fall kann sehr schwierig sein, ihn als Parameter-Standardwert festzulegen. 🎜??
Im Gegensatz zu ||
, ??
Nur für null
oder undefiniert
gilt es nicht für alle virtuellen Werte. 🎜🎜🎜3. Fühlen Sie sich frei, beliebige
Typenany
verwenden. 🎜function createNewMessagesResponse (countOfNewMessages?: number) { if (!!countOfNewMessages) { return `You have ${countOfNewMessages} new messages` } return 'Error: Could not retrieve number of new messages' }
any
verwendet, in unknown
🎜function createNewMessagesResponse (countOfNewMessages?: number) { if (countOfNewMessages !== undefined) { return `You have ${countOfNewMessages} new messages` } return 'Error: Could not retrieve number of new messages' }
any
ist sehr praktisch, da es grundsätzlich alle Typprüfungen deaktiviert. Oft wird any
sogar in offiziell bereitgestellten Typen verwendet. Beispielsweise hat das TypeScript-Team den Typ von response.json()
im obigen Beispiel auf Promise 2cfd83bcbfaff9bacc12c0937fd77054
festgelegt. 🎜any
eingeht, wird jegliche Typprüfung vollständig aufgegeben. Dadurch wird es schwieriger, Fehler zu erkennen. 🎜🎜🎜4. val as SomeType
function createNewMessagesResponse (countOfNewMessages?: number) { if (countOfNewMessages != null) { return `You have ${countOfNewMessages} new messages` } return 'Error: Could not retrieve number of new messages' }
Type Guard
ins Spiel. 🎜function createNewMessagesResponse (countOfNewMessages?: number) { if (countOfNewMessages !== undefined) { return `You have ${countOfNewMessages} new messages` } return 'Error: Could not retrieve number of new messages' }
as SomeOtherType
die Konvertierung beschleunigen, ohne dass die Einstellungen in tsconfig
geändert werden müssen. 🎜Type Guard
stellt sicher, dass alle Prüfungen explizit sind. 🎜🎜🎜5. wie jeder
DigitalProduct
über einen sizeInMb
verfügt. 🎜用一个字母命名泛型
function head<T> (arr: T[]): T | undefined { return arr[0] }
提供完整的描述性类型名称。
function head<Element> (arr: Element[]): Element | undefined { return arr[0] }
这种写法最早来源于C++的范型库,即使是 TS 的官方文档也在用一个字母的名称。它也可以更快地输入,只需要简单的敲下一个字母 T
就可以代替写全名。
通用类型变量也是变量,就像其他变量一样。当 IDE 开始向我们展示变量的类型细节时,我们已经慢慢放弃了用它们的名称描述来变量类型的想法。例如我们现在写代码用 const name ='Daniel'
,而不是 const strName ='Daniel'
。同样,一个字母的变量名通常会令人费解,因为不看声明就很难理解它们的含义。
通过直接将值传给 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' }
编写简短的检测代码看起来更加简洁,使我们能够避免思考实际想要检测的内容。
也许我们应该考虑一下实际要检查的内容。例如上面的例子以不同的方式处理 countOfNewMessages
为 0
的情况。
将非布尔值转换为布尔值。
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' }
对某些人而言,理解 !!
就像是进入 JavaScript 世界的入门仪式。它看起来简短而简洁,如果你对它已经非常习惯了,就会知道它的含义。这是将任意值转换为布尔值的便捷方式。尤其是在如果虚值之间没有明确的语义界限时,例如 null
、undefined
和 ''
。
与很多编码时的便捷方式一样,使用 !!
实际上是混淆了代码的真实含义。这使得新开发人员很难理解代码,无论是对一般开发人员来说还是对 JavaScript 来说都是新手。也很容易引入细微的错误。在对“非布尔类型的值”进行布尔检查时 countOfNewMessages
为 0
的问题在使用 !!
时仍然会存在。
!= 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' }
如果你的代码在 null
和 undefined
之间没有明显的区别,那么 != null
有助于简化对这两种可能性的检查。
尽管 null
在 JavaScript早期很麻烦,但 TypeScript 处于 strict
模式时,它却可以成为这种语言中宝贵的工具。一种常见模式是将 null
值定义为不存在的事物,将 undefined
定义为未知的事物,例如 user.firstName === null
可能意味着用户实际上没有名字,而 user.firstName === undefined
只是意味着我们尚未询问该用户(而 user.firstName ===
的意思是字面意思是 ''
。
原文:https://startup-cto.net/10-bad-typescript-habits-to-break-this-year/
作者:Daniel Bartholomae
译文地址:https://segmentfault.com/a/1190000039368534
更多编程相关知识,请访问:编程入门!!
Das obige ist der detaillierte Inhalt von10 schlechte Gewohnheiten, die Sie beim Schreiben von Code in TypeScript ablegen sollten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!