
一世 爱❤️ TypeScript。
特别是在经历了JavaScript的臭名昭著之后 “无法访问未定义的值” 错误。
但是,即使TypeScript很棒,仍然有一些方法可以自己射击。
在这篇文章中,我将在TypeScript中分享5种不良做法以及如何避免它们。
![]()
1。将错误声明为任何类型
例子
在以下代码段中,我们捕获了错误,然后将其声明为“任何类型”。
async function asyncFunction() {try {const response = await doSomething();return response;} catch (err: any) {toast(`Failed to do something: ${err.message}`);}}
为什么不好❌
不能保证该错误具有字符串类型的消息字段。
不幸的是,由于类型断言,该代码让我们假设确实如此。
该代码可以在特定测试用例的开发中工作,但在生产中可能会严重破坏。
怎么做✅
不要设置错误的类型。应该 unknown 默认情况下。
相反,您可以执行以下任何操作:
选项1: 使用类型保护器检查错误是否正确。
async function asyncFunction() {try {const response = await doSomething();return response;} catch (err) {const toastMessage = hasMessage(err)? `Failed to do something: ${err.message}`: `Failed to do something`;toast(toastMessage);}}// We use a type guard to check firstfunction hasMessage(value: unknown): value is { message: string } {return (value != null &&typeof value === "object" &&"message" in value &&typeof value.message === "string");}// You can also simply check if the error is an instance of Errorconst toastMessage = err instanceof Error? `Failed to do something: ${err.message}`: `Failed to do something`;
- 选项2(推荐): 不要对错误做出假设
与其对错误类型做出假设,不如显式处理每种类型并向用户提供适当的反馈。
如果无法确定特定的错误类型, 最好显示完整的错误信息 而不是部分细节。
![]()
2。具有相同类型的多个连续参数的功能
例子
export function greet(firstName: string,lastName: string,city: string,email: string) {// Do something...}
为什么不好 ❌
您可以不小心以错误的顺序传递参数:
// We inverted firstName and lastName, but TypeScript won't catch thisgreet("Curry", "Stephen", "LA", "stephen.curry@gmail.com")
很难理解每个参数代表什么,尤其是在代码审查期间,当在声明之前看到函数调用时
该怎么办 ✅
使用对象参数来阐明每个字段的目的并最大程度地减少错误的风险。
export function greet(params: {firstName: string;lastName: string;city: string;email: string;}) {// Do something...}
![]()
3。具有多个分支且无返回类型的功能
例子
function getAnimalDetails(animalType: "dog" | "cat" | "cow") {switch (animalType) {case "dog":return { name: "Dog", sound: "Woof" };case "cat":return { name: "Cat", sound: "Meow" };case "cow":return { name: "Cow", sound: "Moo" };default:// This ensures TypeScript catches unhandled cases((_: never) => {})(animalType);}}
为什么不好 ❌
添加新
animalType可能导致返回结构错误的对象。返回类型结构的更改可能会导致代码其他部分难以追踪的问题。
错字可能会导致推断出错误的类型。
该怎么办 ✅
明确指定函数的返回类型:
type Animal = {name: string;sound: string;};function getAnimalDetails(animalType: "dog" | "cat" | "cow"): Animal {switch (animalType) {case "dog":return { name: "Dog", sound: "Woof" };case "cat":return { name: "Cat", sound: "Meow" };case "cow":return { name: "Cow", sound: "Moo" };default:// This ensures TypeScript catches unhandled cases((_: never) => {})(animalType);}}
![]()
4。添加不必要的类型而不是使用可选字段
例子
type Person = {name: string;age: number;}type PersonWithAddress = Person & {address: string;}type PersonWithAddressAndEmail = PersonWithAddress & {email: string;}type PersonWithEmail = Person & {email: string;}
为什么不好 ❌
不缩放:添加新字段需要创建多个新类型
使类型检查更加复杂,需要其他检查 类型防护
导致类型名称混乱和更难维护
该怎么办 ✅
使用可选字段可使您的类型简单且易于维护:
type Person = {name: string;age: number;address?: string;email?: string;};
![]()
5, 使属性在不同组件级别上可选
例子
The disabled 道具在所有组件中都是可选的。
interface TravelFormProps {disabled?: boolean;}export function TravelForm(props: TravelFormProps) {// Uses the date range picker component...}interface DateRangePickerProps {disabled?: boolean;}function DateRangePicker(props: DateRangePickerProps) {// Uses the date picker component...}interface DatePickerProps {disabled?: boolean;}function DatePicker(props: DatePickerProps) {}
为什么不好 ❌
容易忘记通过
disabled道具,导致部分启用表格
该怎么办 ✅
共享字段 需要 用于内部组件。
这将确保适当的道具通过。这对于较低级别的组件尽早发现任何疏忽尤为重要。
在上面的示例中, disabled 现在所有内部组件都需要。
interface TravelFormProps {disabled?: boolean;}export function TravelForm(props: TravelFormProps) {// Uses the date range picker component...}interface DateRangePickerProps {disabled: boolean | undefined;}function DateRangePicker(props: DateRangePickerProps) {// Uses the date picker component...}interface DatePickerProps {disabled: boolean | undefined;}function DatePicker(props: DatePickerProps) {}
注意:如果您正在为库设计组件,则不建议您这样做,因为必填字段需要做更多的工作。
摘要
TypeScript很棒,但是没有工具☺️是完美的。
避免这5个错误将帮助您编写更清洁,更安全,更可维护的代码。

