typescript
简介
本篇文章主要是为了给让大家了解下Typescript
这里将会讲到大家关心的几个问题,简单先简绍了几个与js不同的ts的语法,来探讨ts和传统js的区别
然后从网络上收集整理了一些使用和不使用ts的意见,探讨我们应不应该使用ts,以及ts的适用场景
文章目录
一、介绍
特点
- JavaScript 的超集
- 增加了静态类型系统
- 为大型软件开发而设计的
- 最终编译产生 JavaScript
安装 TypeScript
执行npm install -g typescript
然后就可以在任何地方编译ts文件tsc holle.ts
简单的例子
将下面代码复制到hello.ts
中, 其中使用 : 指定变量的类型
function sayHello(person: string) {
return 'Hello, ' + person;
}
let user = 'Tom';
console.log(sayHello(user));
然后执行
tsc holle.ts
、
这时候会生成一个编译好的文件hello.js
:
function sayHello(person) {
return 'Hello, ' + person;
}
var user = 'Tom';
console.log(sayHello(user));
报错
编译下段代码
// holle.ts
function sayHello(person: string) {
return 'Hello, ' + person;
}
let user = [0, 1, 2];
console.log(sayHello(user));
编译器报错
index.ts(6,22): error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'string'.
因为TypeScript 编译的时候会进行静态检查,如果发现有错误,就会报错
但注意,即使报错,也会生成相应的js文件
二、与js异同
1、变量声明
和es6一样,有let和const
2、基础数据类型
bool、number、string、undefined、arr、obj都有
不同的:
- 元组
允许表示一个已知元素数量和类型的数组
// Declare a tuple type
let x: [string, number];
// Initialize it
x = ['hello', 10]; // OK
- 枚举
像C#等其它语言一样,使用枚举类型可以为一组数值赋予友好的名字。
enum Color {Red, Green, Blue}
let c: Color = Color.Green;
- Any
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
还不清楚类型的变量指定一个类型
- Void
void类型像是与any类型相反,它表示没有任何类型。
function warnUser(): void {
console.log("This is my warning message");
}
- never
表示的是那些永不存在的值的类型。
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {
}
}
- 类型断言
< >表示, 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。
et someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
- 多种类型(联合类型)
可以用|隔开,比如number | string表示可以是number或string类型
3. 接口
TypeScript的核心原则之一是对值所具有的结构进行类型检查,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。
- 简单的接口
定义传入的参数
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
- 可选接口
参数可选
interface SquareConfig {
color?: string;
width?: number;
}
- 只读属性
传入参数只读
interface Point {
readonly x: number;
readonly y: number;
}
let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!
- 描述函数
定义函数输入输出
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
let result = source.search(subString);
return result > -1;
}
- 实现接口
在类中实现接口
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
- 继承接口
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
4. 类
定义了一件事物的抽象特点,包含它的属性和方法
面向对象(OOP)的三大特性:封装、继承、多态
对象实例通过new生成
- 封装
将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据
- 多态
由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比如 Cat 和 Dog 都继承自 Animal,但是分别实现了自己的 eat 方法。此时针对某一个实例,我们无需了解它是 Cat 还是 Dog,就可以直接调用 eat 方法,程序会自动判断出来应该如何执行 eat
- 继承
子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
class Animal {
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}m.`);
}
}
class Dog extends Animal {
bark() {
console.log('Woof! Woof!');
}
}
const dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();
- 存取器(getter & setter)
用以改变属性的读取和赋值行为
- 修饰符(Modifiers)
修饰符是一些关键字,用于限定成员或类型的性质。如 public 和 private
- 抽象类(Abstract Class)
抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现
这个和接口有点像,有兴趣可以看下接口和抽象类的区别
5. 泛型
在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。
// 使用泛型前
function identity(arg: number): number {
return arg;
}
// 使用泛型后
function identity<T>(arg: T): T {
return arg;
}
T帮助我们捕获用户传入的类型,使用后再返回类型T的值
6.使用第三方模块
- 需要相应的声明文件(.d.ts文件)
一般情况下在 TypeScript 中是不能”直接“使用 npm 上的模块
不是使用 TypeScript 编写的模块,也可以通过手动编写声明文件来兼容 TypeScript。
- 通过 npm install @types/xxx 来安装模块声明文件
TypeScript 官方建立了一个名叫 DefinitelyTyped 的仓库,任何人都可以通过 GitHub 在上面修改或者新增 npm 模块的声明文件
最后
还有其他类型就不一一详细介绍了,具体可以参照官方文档(中文版)
三、使用与不使用的理由
1. 不使用的理由
- npm装上的那些xxxjs库都是没有任何类型信息的
(只能使用诸如definitelytyped之类的ts定义库,里面包含了常用js库(如jquery)对应的TypeScript兼容的强类型定义文件(xxx.d.ts),使得在其他的TypeScript文件中可以通过引用这些定义文件来实现ts到js的调用的)
- TS+框架会有很多坑
-
比如 :immutable.js + Typescript 坑很多
-
必须学习框架+全家桶的各种暴露出来的d.ts
-
TS彻底替代babel会出问题,比如不能享受babel-plugin-import这种按需引入的Babel插件了
-
虽然声称可以在任何场景下替代JS,但前提是有良好的框架支撑
-
vue2.5以前对TS的支持不是特别好,但Vue本身支持不错,周边那些东西缺没那么好 GitHub: 2K
-
react 和 Angular 本身和周边支持良好 ,GitHub: 11K 和 10K
-
语法检测和ESlint部分重复
总结,项目不大,后期不用维护的项目没有必要使用,项目主要依赖库要对TS支持良好,冷门的小项目没有必要用TS
2. 使用的理由
-
侦测错误,提供了一套强类型的规范,统一团队代码风格,更方便准确地检查错误
-
在项目初期就进行,类型注释,和接口定义,方便指导开发,
-
文档,新人来了也可以直接看文档接手项目
抽象,前端圈子里有这么一个流行语『自从用了Typescript之后,再也不想用JavaScript了』
-
静态类型语言,在编译的时候就能发现问题
-
方便代码重构
比如初期定义了一个string,但项目进行到一半说要改成number,如果普通的js,改一个不会报错,eslint则不会识别没有执行到文件的类型错误,而在TS强类型在编译器检验下,在编译时进行类型分析,改一个,其他需要改动的地方无可型盾
- antd使用的是TS
总结,这些特点还是挺诱人的,大型项目可以使用,总体来说,学习成本有,但熟悉过es6的人来说,门槛不算太高,学起来比较像写java。