2019 年开始使用 TypeScript
2019 年开始使用 TypeScript
2019 年开始使用 TypeScript
最初发布在我的博客上
根据2018 年 Stack Overflow 开发者调查,TypeScript 作为编程语言比 JavaScript 更受“喜爱”。TypeScript 之所以受到 JavaScript 开发者的青睐,是因为在 JavaScript 中添加类型可以让你在运行代码之前发现错误。TypeScript 编译器提供的错误信息可以很好地指导如何修复错误。添加类型还能让代码编辑器提供一些更高级的功能,例如代码补全、项目范围的重构和自动模块导入。
2018 年 Stack Overflow 开发者调查中“最喜爱的编程语言”调查问题的结果
如果您将 TypeScript 视为一门全新的编程语言,学习它可能会令人望而生畏。然而,TypeScript 只是 JavaScript 的附加层,您无需了解 TypeScript 的所有语法即可开始使用。TypeScript 允许您轻松地将 JavaScript 文件转换为 TypeScript,只需将文件扩展名从 更改为 即可.js
,.ts
所有代码都将正确编译为 TypeScript。如果您想在 TypeScript 文件中强制执行更大比例的类型覆盖,可以配置 TypeScript 以进行更严格的限制,但这只有在您更熟悉该语言后才能实现。
本文旨在帮助您快速掌握在标准 TypeScript 项目中通常会遇到的大约95% 的场景。对于剩下的 5%,Google 是您的好朋友,我在文章底部添加了一些有用的 TypeScript 资源链接。
设置 TypeScript
当然,要开始编写正确编译的 TypeScript,需要一个正确配置的开发环境。
1.安装 TypeScript 编译器
首先,需要安装 TypeScript 编译器,以便将 TypeScript 文件转换为 JavaScript 文件。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
从命令行运行的命令,用于在计算机上全局或本地安装 TypeScript
2. 确保你的编辑器支持 TypeScript
您需要确保您的编辑器已正确配置,可以使用 TypeScript。例如,您可能需要安装一个插件(例如,如果使用 Atom 编辑器,则需要安装atom-typescript),以便在编辑器中充分利用 TypeScript。如果您使用 VS Code,则 TypeScript 支持是内置的,因此无需任何扩展 😎。
3.创建 **tsconfig.json**
文件
该tsconfig.json
文件用于配置 TypeScript 项目设置。该tsconfig.json
文件应放在项目的根目录中。该文件允许您使用不同的选项配置 TypeScript 编译器。
tsconfig.json
如果您只想让 TypeScript 工作,则可以包含一个空的 JSON 对象,但如果您需要 TypeScript 编译器表现出不同的行为(例如在特定的输出目录中输出转换后的 JavaScript 文件),您可以阅读有关可以配置哪些设置的更多信息。
注意:您还可以运行
_tsc --init_
生成一个_tsconfig.json_
文件,其中设置了一些默认选项,并注释掉了一些其他选项
4. 将 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');
TypeScript 语法示例
应该转换为这个 JavaScript 文件...
var greeting = function(person) {
console.log('Good day ' + person);
};
greeting('Daniel');
通过转换 TypeScript 生成的 JavaScript 文件
如果您希望 TypeScript 编译器监视 TypeScript 文件中的更改并自动触发文件的转换.ts
,您可以在项目的存储库中.js
运行. 命令。tsc -p
在 VS Code 中,您可以使用⌘⇧B
调出一个菜单,该菜单可以在正常模式或监视模式(分别为 或 )下运行转译tsc:build
器tsc:watch
。
理解静态和动态类型
JavaScript 有 7 种动态类型:
- 不明确的
- 无效的
- 布尔值
- 数字
- 细绳
- 象征
- 目的
上述类型被称为动态的,因为它们是在运行时使用的。
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 chiken cross the road?
A: ${punchline}
`;
使用模板文字进行字符串类型注释
number
任何浮点数都被赋予 的类型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
Atuple
是一个包含固定数量元素和相关类型的数组。
let myFavoriteTuple: [string, number, boolean];
myFavoriteTuple = ['chair', 20, true]; // ✅
myFavoriteTuple = [5, 20, true]; // ❌ - The first element should be a string, not a number
声明一个包含 3 个元素的元组,然后为该元组赋值
enum
枚举enum
是一种将名称与常量值关联起来的方法,该常量值可以是数字或字符串。当你需要一组具有描述性名称的不同值时,枚举非常有用。
默认情况下,枚举会分配从 开始的数字,0
并且1
枚举的每个成员都会增加 。
enum Sizes {
Small,
Medium,
Large,
}
Sizes.Small; // => 0
Sizes.Medium; // => 1
Sizes.Large; // => 2
从 9 开始的枚举示例
第一个值可以设置为除 之外的值0
。
enum Sizes {
Small = 1,
Medium,
Large,
}
Sizes.Small; // => 1
Sizes.Medium; // => 2
Sizes.Large; // => 3
枚举从非 0 值开始的示例
枚举默认分配有数字,但是也可以将字符串值分配给枚举。
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
any 类型的示例
any
在开始使用 TypeScript 时,它可能会经常被使用。但是,最好尽量减少它的使用,any
因为当编译器无法识别变量关联的类型时,TypeScript 的实用性会降低。
void
当没有与任何类型关联的对象时,void
应该使用该类型。它最常用于指定不返回任何内容的函数的返回值。
const darkestPlaceOnEarth = (): void => {
console.log('Marianas Trench');
};
使用 void 类型的示例
null
和undefined
和 都null
对应于 JavaScript 中常见的和值undefined
的类型。这些类型单独使用时用处不大。null
undefined
let anUndefinedVariable: undefined = undefined;
let aNullVariable: null = null;
如何使用 null 和 undefined 类型的示例
默认情况下,null
和undefined
类型是所有其他类型的子类型,这意味着类型为 的变量string
可以被赋值为null
或undefined
。这通常是不受欢迎的行为,因此通常建议strictNullChecks
在tsconfig.json
文件中将编译器选项设置为true
。将选项设置strictNullChecks
为true
,则需要将null
和undefined
明确设置为变量的类型。
类型推断
幸运的是,你不必在代码的任何地方都绝对指定类型,因为 TypeScript 具有所谓的类型推断。类型推断是 TypeScript 编译器用来自动确定类型的方法。
基本类型推断
TypeScript 可以在变量初始化、设置默认参数值以及确定函数返回值时推断类型。
// Variable initialization
let x = 10; // x is given the number type
类型推断的示例,其中 x 变量具有推断的数字类型
在上面的例子中,x
被分配了一个数字,TypeScript 将该x
变量与 的类型关联起来number
。
// 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
根据函数参数的类型,推断数字类型分配给 add 函数的返回值
在上面的例子中,由于 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'
最佳通用类型算法确定只应允许数字和空类型作为列表数组的元素
在上面的例子中,数组由number
和null
类型组成,因此 TypeScript 只期望number
和null
值成为数组的一部分。
类型注解
当类型推断系统不够用时,您将需要在变量和对象上声明类型。
基本类型
基本静态类型部分介绍的所有类型都可以使用:
后跟类型名称来声明。
let aBoolean: boolean = true;
let aNumber: number = 10;
let aString: string = 'woohoo';
注释基本类型的示例
数组
如讨论类型的部分所示array
,数组可以用两种方式之一进行注释。
// 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 Animal = {
kind: string;
weight: number;
};
let dog: Animal;
dog = {
kind: 'mammal',
weight: 10,
}; // ✅
dog = {
kind: true,
weight: 10,
}; // ❌ - kind should be a string
使用类型别名注释类型
在使用接口或类型别名方面,最佳实践似乎是在代码库中只选择其中一种,interface
并type
保持一致。但是,如果编写的是可供他人使用的第三方公共 API,则应使用interface
类型。
如果您想更详细地比较类型别名和接口,我推荐Matin 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
是一个字符串,因此创建的数组的所有元素都会被设置为 类型string
。
需要注意的是,按照惯例,泛型类型使用单个字母(例如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
使用元组类型注释变量
可选类型
在某些情况下,函数参数或对象属性可能是可选的。在这种情况下,?
使用 a 来表示这些可选值。
// 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 手册(官方 TypeScript 文档)
TypeScript 深度探索(在线 TypeScript 指南)
理解 TypeScript 的类型注解(很棒的 TypeScript 入门文章)
文章来源:https://dev.to/robertcoopercode/get-started-with-typescript-in-2019-6hd