精进TypeScript--优先选择类型声明而不是类型断言

要记住的事:

  • 优先选择类型声明(:Type)而不是类型断言(as Type)
  • 知道如何注释一个箭头函数的返回类型
  • 当你知道一些类型而TypeScript不知道时,使用类型断言和非空断言

TypeScript似乎有两种方法来给变量赋值并赋予一个类型:

interface Person { name: string; }

const alice: Person = { name: 'Alice' }; // 类型是Person
const bob = { name: 'Bob' } as Person; // 类型是Person

虽然这两种方法的目的相似,实际上完全不同。第一种是给变量添加了一个类型声明,并确保值符合类型。第二种执行了一个类型断言,这告诉TypeScript,尽管它推断出了类型,但你更了解它,并希望类型是Person.
一般来说,你应该更喜欢类型声明而不是类型断言。因为:

const alice: Person = {}; // 类型“{}”中缺少属性“name”,但在类型Person中为必选
const alice: Person = {
	name: 'Alice',
	occupation: 'Developer' // ~~提示错误,occupation不在类型“Person”中
};

const bob = {} as Person; // 没错误
const bob = {
	name: 'Bob',
	occupation: 'Developer'
} as Person; // 没错误

类型声明验证了这个值符合接口要求,如果不符合,TypeScript就会标记一个错误。类型断言通过推断告诉类型检查器,不管出于什么原因,你比它更了解这个错误。类型声明提供了透明的安全检查,你应该使用它,除非你有特定的理由使用类型断言。

该如何对箭头函数使用类型声明并不总是很清楚的。比如:

const people = ['alice', 'bob', 'jan'].map(name => ({name}));
// { name: string; }[]  ...但我们需要Person

在这里使用类型断言比较容易:

const people = ['alice', 'bob', 'jan'].map(name => ({name} as Person));
// 类型是 Peron[],但这和更直接的类型断言一样
const people = ['alice', 'bob', 'jan'].map(name => ({} as Person));

那么如何在这种情况下使用类型声明?如下声明箭头函数的返回类型:

const people = ['alice', 'bob', 'jan'].map(
	(name): Person => ({name})
); // 类型是Person[]

这样执行所有与前面一样的值检查。(name): Person推断出name的类型,并指定返回的类型应该是Person,这里的括号很重要!

但是,在一个较长的函数调用链的上下文中,可能有必要或希望尽早出现命名的类型,这将有助于在错误发生的地方标记错误。

那么什么时候应该使用类型断言呢?当你确实比TypeScript知道更多关于类型的信息时,类型断言是最有意义的。下面示例中,TypeScript无法访问你的页面DOM,它无法知道#myButton是一个按钮元素,也不知道事件中currentTarget应该是同一个按钮。由于你有TypeScript没有的信息,因此类型断言在这里是有意义的。

document.querySelector('#myButton').addEventListener('click', e => {
	e.currentTarget // 类型是EventTarget
	const button = e.currentTarget as HTMLButtonElement; // button类型是HTMLButtonElement
});

类型断言也有其局限性:它们不能让你在任意类型之间进行转换。一般,我们可以使用类型断言在A和B之间进行转换,只要其中一个是另一的子集。比如HTMLButtonElement是EventTarget的子集,e.currentTarget as HTMLButtonElement是可以的,Person是{}的子类型,{ } as Person是可以的。
但是我们不能在Person和HTMLElement之间进行转换,两者都不是对方的子类型。

interface Person { name: string; }
const body = document.body;
const el = body as Person // ~~提示错误,这两个类型没有充分地重叠。如果有意为之,请先将表达式转换为“unknown”。

每个类型都是unknown的子类型,所以涉及unknown的断言总是正确的,这让你可以在任意类型之间进行转换,但至少你是显式地在做一些令人生疑的事情。

const el = document.body as unknown as Person; // OK
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~卷心菜~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值