
基于2018年Stack Overflow Developer的调研,TypeScript
做为编程语言比JavaScript更受“喜好”。TypeScript在js开发者中这么受喜好的缘由是:在你运行代码前,添加到javascript中的类型有助你发现错误(代码)。TypeScript编译器提供的错误能够很好的引导你如何修复代码错误。往javascript中添加类型同时有助代码编辑器提供一些高级的功能,例如代码完成,项目范围的重构和自动模块的导入。javascript

若是你认为TypeScript是一门全新的编程语言,那么学习它可能使人生畏。然而,TypeScript只是JavaScript的一个附加层(超集),在使用TypeScript前,你无需了解它的每一个语法。TypeScript容许你经过更改文件的后缀名.js
为.ts
来轻松的转换javascript文件,而且全部的代码将做为TypeScript来正确编译。若是你想在TypeScript文件中强制执行更广的类型覆盖百分比,你能够将TypeScript配置得更具局限性,一旦你熟悉该语言了,你就能够完成此操做。html
本文旨在带你快速了解一个标准的TypeScript项目中会遇到的95%的场景。剩余的5%,嗯,你能够google,还有,我会在本文底部放些有用的TypeScript资源连接。java
配置TypeScript
固然,要开始编写能正确编译的TypeScript(文件),正确配置开发环境是必要的。git
一、安装TypeScript编译器github
首先,为了可以将TypeScript文件转换成JavaScript文件,咱们须要安装TypeScript编译器。安装TypeScript可全局安装(文件系统中安装,能够在任何位置使用)或者本地安装(仅在项目级别可以使用)。【我的偏向后者】算法
# NPM Installation Method
npm install --global typescript # Global installation
npm install --save-dev typescript # Local installation
# Yarn Installation Method
yarn global add typescript # Global installation
yarn add --dev typescript # Local installation
复制代码
二、确保你的编辑器设置为支持TypeScripttypescript
你须要确保正确配置了你的编辑器以使用TypeScript。好比,为了在编辑器中能更好得使用TypeScript,你须要安装一个插件(若是你使用atom,你能够安装 atom-typescript)。若是你使用的是VS Code编辑器
,那么你不须要安装额外的插件了,由于它内置了TypeScript的支持。😎npm
三、新建tsconfig.json文件编程
tsconfig.json文件是用来配置TypeScript项目设置。它应该放在项目的根目录中。该文件容许你使用不一样的选项配置TypeScript编译器。json
若是你仅仅是想TypeScript生效的话,你只须要tsconfig.json文件中包含一个空JSON对象,可是,若是你须要TypeScript编译器的有不一样的行为(好比在特定的输出目录中输出编译后的JavaScript文件),你能够阅读更多有关能够配置哪些设置的(内容)。
备注:你也能够经过运行
tsc --init
去生成一个tsconfig.json文件,其中为你设置了些默认选项,还有一些被注释掉的其余选项。
四、将TypeScript转化为JavaScript
为了将你的TypeScript代码转化成JavaScript代码,须要在控制台上跑tsc命令。运行tsc命令将告诉TypeScript编译器去搜索tsconfig.json
文件,该文件将肯定项目的根目录以及编译TypeScript并将.ts
文件转换为.js
文件时用的选项。
为了快速验证设置生效,你能够建立一个测试的TypeScript文件,而后在命令行中运行tsc
,以后查看下TypeScript文件旁边是否生成了JavaScript文件。
举个例子,TypeScript文件以下...
const greeting = (person: string) => {
console.log('Good day ' + person);
};
greeting('Daniel');
复制代码
应该被转换为下面这个JavaScript文件了...
var greeting = function(person) {
console.log('Good day ' + person);
};
greeting('Daniel');
复制代码
若是你想TypeScript编译器(动态)监视TypeScript文件内容的变动,并自动将.ts
文件转换成.js
文件,你能够在你项目的仓库(命令行)中运行tsc -p
。
在VS Code(编辑器)中,你可使用⌘⇧B调出一个菜单,该菜单(包含)能够在正常模式和监视模式下运行转换程序(分别对应tsc:build
和tsc:watch
)。

了解静态和动态类型
JavaScript附带7种动态类型:
- Undefined
- Null
- Boolean
- Number
- String
- Symbol
- Object
上面的类型被称为动态类型,由于它们在运行时使用。
TypeScript为JavaScript语言带来了静态类型,而且这些类型在编译时(无需运行代码)被肯定。静态类型能够预测动态类型的值,这能够帮助在无需运行代码的状况下警告你可能出现的错误。
基本静态类型
好吧,咱们来深刻研究下TypeScript的语法。如下是TypeScript中最多见的类型。
备注:我遗漏了never和object类型,由于根据个人经验,它们并不被常用。
boolean
你已经很了解true
和false
值了。
let isAwesome: boolean = true;
复制代码
string
文本数据用单引号('')或双引号("")或后标记(``)【也称模版字符】包围。
let name: string = 'Chris';
let breed: string = 'Border Collie';
复制代码
若是你使用后标志,该字符串被称为模版文字,能够在里面插入表达式。
let punchline: string = 'Because it was free-range.';
let joke: string = ` Q: Why did the chicken cross the road? A: ${punchline} `;
复制代码
number
任何浮点数都给定为数字类型。做为TypeScript的一部分,支持的四种类型的数字文字是二进制,十进制,八进制和十六进制。
let decimalNumber: number = 42;
let binaryNumber: number = 0b101010; // => 42
let octalNumber: number = 0o52; // => 42
let hexadecimalNumber: number = 0x2a; // => 42
复制代码
备注:并非只有你一我的对二进制,八进制和十六进制数字感到困惑。
array
TypeScript中有两种书写数组类型的方式。第一种是[]后缀在须要查找的数组元素类型。
let myPetFamily: string[] = ['rocket', 'fluffly', 'harry'];
复制代码
另外一种可替代的方式是,Array后跟要查找的数组元素类型的Array
类型(使用尖括号包含)。
let myPetFamily: Array<string> = ['rocket', 'fluffly', 'harry'];
复制代码
tuple
元组是一个包含固定数量的元素和相关类型的数组。
let myFavoriteTuple: [string, number, boolean];
myFavoriteTuple = ['chair', 20, true]; // ✅
myFavoriteTuple = [5, 20, true]; // ❌ - The first element should be a string, not a number
复制代码
enum
枚举将名称和常量值关联,能够是数字或者字符串。当你想一组具备关联性的描述名称的不一样值,枚举就颇有用处了。
默认,为枚举分配从0开始的值,接下来的值为(上一个枚举值)加1。
enum Sizes {
Small,
Medium,
Large,
}
Sizes.Small; // => 0
Sizes.Medium; // => 1
Sizes.Large; // => 2
复制代码
第一个值也能够设置为非0的值。
enum Sizes {
Small = 1,
Medium,
Large,
}
Sizes.Small; // => 1
Sizes.Medium; // => 2
Sizes.Large; // => 3
复制代码
枚举默认是被分配数字,然而,字符串也能够被分配到一个枚举中的。
enum ThemeColors {
Primary = 'primary',
Secondary = 'secondary',
Dark = 'dark',
DarkSecondary = 'darkSecondary',
}
复制代码
any
若是变量的类型未知,而且咱们并不但愿类型检查器在编译时抱怨,则可使用any
类型。
let whoKnows: any = 4; // assigned a number
whoKnows = 'a beautiful string'; // can be reassigned to a string
whoKnows = false; // can be reassigned to a boolean
复制代码
在开始使用TypeScript的时,可能会频繁使用any
类型。然而,最好尝试减小any
的使用,由于当编译器不知道与变量相关的类型时,TypeScript的有用性会下降。
void
当没有与事物相关类型的时候,void
类型应该被使用。在指定不返回任何内容的函数返回值时,最经常使用它。
const darkestPlaceOnEarth = (): void => {
console.log('Marianas Trench');
};
复制代码
null和undefined
null和undefined都对应你在javascript中看到的null和undefined值的类型。这些类型在单独使用的时候不是颇有用。
let anUndefinedVariable: undefined = undefined;
let aNullVariable: null = null;
复制代码
默认状况下,null和undefined类型是其余类型的子类型,这意味着能够为string类型的变量赋值为null或者undefined。这一般是不合理的行为,因此一般建议将tsconfig.json
文件中的strictNullChecks编译器选项设置为true。将strictNullChecks设置为true,会使null和undefined须要显示设置为变量的类型。
类型推断
幸运的是,你不须要在代码中所有位置指定类型,由于TypeScript具备类型推断。类型推断是TypeScript编译器用来自行决定类型的(内容)。
基本类型推断
TypeScript能够在变量初始化期间,设置默认参数以及肯定函数返回值时推断类型。
// Variable initialization
let x = 10; // x is given the number type
复制代码
在上面的例子中,x
被分配了数字,TypeScript会以number
类型将x
变量关联起来。
// Default function parameters
const tweetLength = (message = 'A default tweet') => {
return message.length;
};
复制代码
在上面的例子中,message参数被赋予了一个类型为string的默认值,所以TypeScript编译器会推断出message的类型是string,所以在访问length属性的时候并不会抛出编译错误。
function add(a: number, b: number) {
return a + b;
}
const result = add(2, 4);
result.toFixed(2); // ✅
result.length; // ❌ - length is not a property of number types
复制代码
在上面这个例子中,由于TypeScript告诉add
函数,它的参数都是number
类型,那么能够推断得出返回的类型也应该是number
。
最佳通用类型推断
从多种可能的类型中推断类型时,TypeScript使用最佳通用类型算法来选择适用于全部其余候选类型的类型。
let list = [10, 22, 4, null, 5];
list.push(6); // ✅
list.push(null); // ✅
list.push('nope'); // ❌ - type 'string' is neither of type 'number' or 'null'
复制代码
在上面的例子中,数组(list)是由number
或null
类型组成的,所以TypeScript只但愿number
或null
类型的值加入数组。
类型注释
当类型推断系统不够用的时,你须要在变量和对象上声明类型。
基本类型
在(上面)基本静态类型章节的介绍中,全部的类型都使用:
后跟类型名来声明。
let aBoolean: boolean = true;
let aNumber: number = 10;
let aString: string = 'woohoo';
复制代码
Arrays
在(上面)讲到的array
类型的章节中,arrays能够经过两种方式的其中一种进行注释。
// First method is using the square bracket notation
let messageArray: string[] = ['hello', 'my name is fred', 'bye'];
// Second method uses the Array keyword notation
let messageArray: Array<string> = ['hello', 'my name is fred', 'bye'];
复制代码
接口
将多种类型的注释组合到一块儿的一种方法是使用接口。
interface Animal {
kind: string;
weight: number;
}
let dog: Animal;
dog = {
kind: 'mammal',
weight: 10,
}; // ✅
dog = {
kind: true,
weight: 10,
}; // ❌ - kind should be a string
复制代码
类型别名
TypeScript使用Type Alias指定多个类型注释,这事(让人)有些疑惑。【下面讲到】
type Animal = {
kind: string;
weight: number;
};
let dog: Animal;
dog = {
kind: 'mammal',
weight: 10,
}; // ✅
dog = {
kind: true,
weight: 10,
}; // ❌ - kind should be a string
复制代码
在使用接口或类型别名这方面,最佳的作法彷佛是,在代码库保持一致状况下,一般选择接口类型或类型别名。可是,若是编写其余人可使用的第三方的公共API,就要使用接口类型了。
若是你想了解更多关于type alias
和interface
的比较的话,我推荐你看Martin Hochel的这篇文章。
内联注释
相比建立一个可复用的接口,有时内联注释类型可能更合适。
let dog: {
kind: string;
weight: number;
};
dog = {
kind: 'mammal',
weight: 10,
}; // ✅
dog = {
kind: true,
weight: 10,
}; // ❌ - kind should be a string
复制代码
泛型
某些状况下,变量的特定类型可有可无,可是应强制执行不一样变量和类型之间的关系。针对这些状况,应该使用泛型类型。
const fillArray = <T>(len: number, elem: T) => {
return new Array<T>(len).fill(elem);
};
const newArray = fillArray<string>(3, 'hi'); // => ['hi', 'hi', 'hi']
newArray.push('bye'); // ✅
newArray.push(true); // ❌ - only strings can be added to the array
复制代码
上面的示例中有一个泛型类型T
,它对应于传递给fillArray
函数的第二个参数类型。传递给fillArray
函数的第二个参数是一个字符串,所以建立的数组将其全部元素设置为具备字符串类型。
应该注意的是,按照惯例,单个(大写)字母用于泛型类型(好比:T
或K
)。但是,并不限制你使用更具备描述性的名称来表示你的泛型类型。下面示例就是为所提供的泛型类型使用了更具备描述性的名称:
const fillArray = <ArrayElementType>(len: number, elem: ArrayElementType) => {
return new Array<ArrayElementType>(len).fill(elem);
};
const newArray = fillArray<string>(3, 'hi'); // => ['hi', 'hi', 'hi']
newArray.push('bye'); // ✅
newArray.push(true); // ❌ - only strings can be added to the array
复制代码
联合类型
在类型能够是多种类型之一的状况下,使用|
分隔符隔开不一样类型的选项来使用联合类型。
// The `name` parameter can be either a string or null
const sayHappyBirthdayOnFacebook = (name: string | null) => {
if (name === null) {
console.log('Happy birthday!');
} else {
console.log(`Happy birthday ${name}!`);
}
};
sayHappyBirthdayOnFacebook(null); // => "Happy birthday!"
sayHappyBirthdayOnFacebook('Jeremy'); // => "Happy birthday Jeremy!"
复制代码
交集类型
交集类型使用&
符号将多个类型组合在一块儿。这和(上面的)联合类型不一样,由于联合类型是表示结果的类型是列出的类型之一,而交集类型则表示结果的类型是全部列出类型的集合。
type Student = {
id: string;
age: number;
};
type Employee = {
companyId: string;
};
let person: Student & Employee;
person.age = 21; // ✅
person.companyId = 'SP302334'; // ✅
person.id = '10033402'; // ✅
person.name = 'Henry'; // ❌ - name does not exist in Student & Employee
复制代码
元组类型
元组类型使用一个:
符号,其后跟一个使用中括号包含且逗号分隔的类型列表表示。
let list: [string, string, number];
list = ['apple', 'banana', 8.75]; // ✅
list = ['apple', true, 8.75]; // ❌ - the second argument should be of type string
list = ['apple', 'banana', 10.33, 3]; // ❌ - the tuple specifies a length of 3, not 4
复制代码
可选类型
可能存在函数参数或者对象属性是可选的状况。在这些状况下,使用?
来表示这些可选值。
// Optional function parameter
function callMom(message?: string) {
if (!message) {
console.log('Hi mom. Love you. Bye.');
} else {
console.log(message);
}
}
// Interface describing an object containing an optional property
interface Person {
name: string;
age: number;
favoriteColor?: string; // This property is optional
}
复制代码
有帮助的资源
本文中未涉及到的TypeScript内容,我推荐如下的资源。
TypeScript Handbook (Official TypeScript docs)
TypeScript Deep Dive (Online TypeScript Guide)
Understanding TypeScript's Type Annotation (Great introductory TypeScript article)
本文同步分享在 博客“Jimmy”(JueJin)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。