精进TypeScript--使用ECMAScript特性,而非TypeScript特性

本文探讨了TypeScript与JavaScript的关系,指出TypeScript是JavaScript的超集,强调了其类型系统、参数属性、命名空间/模块系统以及装饰器的使用。文章提醒开发者注意TypeScript与JavaScript核心特性的差异,尤其是在使用装饰器时的条件限制。
摘要由CSDN通过智能技术生成

微软在2010年第一次开始研究TypeScript时,大家对JavaScript的普遍态度是:这是一种有问题的语言,需要被修正。对于框架和源到源编译器来说,为JavaScript添加缺失的特性,如类、装饰器和模块系统,是很常见的。TypeScript也不例外,它早起版本也包括了类、枚举和模块的自制版本。
TC39–管理JavaScript的标准机构,在核心JavaScript语言中添加了许多同样的特性。而这些添加的特性与TypeScript中存在的特性不兼容。“是采用标准中的新特性还是破坏现有的代码?”,TypeScript选择了后者,并最终阐述了它目前的管理原则:TC39定义了运行时,而TypeScript只在类型空间上进行创新。
而在做出这个决定之前,它还保留了一些特性。认识和理解这些特性很重要,因为它们不符合语言其他部分的模式。一般来说,我们建议避免使用它们,以是两者关系尽可能保持清晰。

理解TypeScript和JavaScript的关系:

  • TypeScript 是 JavaScript 的超集。换句话说,所有 JavaScript 程序已经是 TypeScript 程序了。TypeScript具有一些自己的语法,因此 TypeScript 程序通常不是合法的 JavaScript 程序。
  • TypeScript 添加了一个类型系统,该类型系统可对 JavaScript 的运行时行为进行建模,并尝试发现将在运行时引发异常的代码。但不要期望它会标记所有异常。通过类型检查器的代码仍可能在运行时抛出异常。
  • 尽管 TypeScript 的类型系统在很大程度上对 JavaScript 的运行时行为进行了建模,但仍有一些 JavaScript 允许的行为,TypeScript 选择禁止,如使用错误数量的参数调用函数。

参数属性

当初始化一个类时,通常会将属性分配给一个构造函数参数:

class Person {
	name: string;
	constructor(name: string) {
		this.name = name;
	}
}
// TypeScript提供了一个更紧凑的语法
class Person {
	constructor(public name: string) {}
}

这被称为“参数属性”,上面两者代码等价。但参数属性有几个需要注意的问题:

  • 它们是少数几个在编译成JavaScript时会生成代码的结构之一。一般来说,编译只涉及擦除类型(而非增添代码)
  • 因为参数只在生成的代码中使用,所以源代码看似有未使用的参数
  • 参数和非参数属性的混用会隐藏你的类的设计

例如:

class Person {
	first: string;
	last: string;
	consctructor(public name: string) {
		[this.first, this.last] = name.split(' ');
	}
}

这个类有三个属性(first, last, name),但这很难从代码中读明白,因为只有两个属性列在构造函数之前。如果构造函数也接收其他参数,情况会更遭。

如果你的类只有参数属性组成,而没有方法,你可以考虑把它做成interface,并使用对象字面量。请记住,对由于结构类型,两者是可以相互赋值的:

class Person {
	constructor(public name: string) {}
}
const p: Person = {name: 'Bob'}; // OK

关于参数属性,大家意见不一。有人很欣赏它们能够节省按键。但,它们与TypeScript其余部分的模式不相符,事实上这可能会让其他开发者难以摸清这种模式。尽量避免通过混用参数和非参数属性来隐藏你的类的设计。

命名空间和三斜线导入

在ECMAScript 2015之前,JavaScript并没有一个官方的模块系统,而是在不同的环境中以不同的方式加上了这个确实的特性。Node.js使用了require和module.exports,而AMD使用了一个带有回调的define函数。

TypeScript也用自己的模块系统填补了这个空白,它通过module关键字和“三斜线”导入来完成。在ECMAScript 2015增加了官方模块系统后,TypeScript增加了namespace作为module的同义词,以避免混淆。

namespace foo {
	function bar() {}
}
/// <reference path="other.ts">
foo.bar();

在类型声明之外,三斜线导入和module关键字只是一个历史遗迹。而在你的代码中应该使用ECMAScript 2015风格的模块(import 和 export)。

装饰器

装饰器可以用来标注和修改类、方法和属性。例如,你可以定义一个logged注解,来对类上的某个方法的所有调用打印日志:

class Greeter {
	greeting: string;
	constructor(message: string) {
		this.greeting = message;
	}
	
	@logged
	greet() {
		return `Hello, ${this.greeting}`;
	}
}

function logged(target: any, name: string, descriptor: PropertyDescriptor) {
	const fn = target[name];
	descriptor.value = function() {
		console.log(`Calling ${name}`);
		return fn.apply(this, arguments);
	};
}

console.log(new Greeter('Dave').greet());
// Calling greet
// Hello, Dave

这个特性最初是为了支持Angular框架而添加的,需要在tsconfig.json中设置experimentalDecorators属性。除非你正在使用Angular或其它需要注解的框架,并且在它们被标准化之前,不要使用TypeScript的装饰器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

~卷心菜~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值