Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【译】2019年开始使用Typescript #8

Open
reng99 opened this issue Feb 17, 2019 · 0 comments
Open

【译】2019年开始使用Typescript #8

reng99 opened this issue Feb 17, 2019 · 0 comments
Labels
blog a single blog translation translate somehing typescript typescript tag

Comments

@reng99
Copy link
Owner

reng99 commented Feb 17, 2019

banner

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

more loved programming languages

如果你认为TypeScript是一门全新的编程语言,那么学习它可能令人生畏。然而,TypeScript只是JavaScript的一个附加层(超集),在使用TypeScript前,你无需了解它的每个语法。TypeScript允许你通过更改文件的后缀名.js.ts来轻松的转换javascript文件,并且所有的代码将作为TypeScript来正确编译。如果你想在TypeScript文件中强制执行更广的类型覆盖百分比,你可以将TypeScript配置得更具局限性,一旦你熟悉该语言了,你就可以完成此操作。

本文旨在带你快速了解一个标准的TypeScript项目中会遇到的95%的场景。剩余的5%,嗯,你可以google,还有,我会在本文底部放些有用的TypeScript资源链接。

配置TypeScript

当然,要开始编写能正确编译的TypeScript(文件),正确配置开发环境是必要的。

1、安装TypeScript编译器

首先,为了能够将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

2、确保你的编辑器设置为支持TypeScript

你需要确保正确配置了你的编辑器以使用TypeScript。比如,为了在编辑器中能更好得使用TypeScript,你需要安装一个插件(如果你使用atom,你可以安装 atom-typescript)。如果你使用的是VS Code编辑器,那么你不需要安装额外的插件了,因为它内置了TypeScript的支持。😎

3、新建tsconfig.json文件

tsconfig.json文件是用来配置TypeScript项目设置。它应该放在项目的根目录中。该文件允许你使用不同的选项配置TypeScript编译器。

如果你仅仅是想TypeScript生效的话,你只需要tsconfig.json文件中包含一个空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');

应该被转换为下面这个JavaScript文件了...

var greeting = function(person) {
    console.log('Good day ' + person);
};
greeting('Daniel');

如果你想TypeScript编译器(动态)监视TypeScript文件内容的变更,并自动将.ts文件转换成.js文件,你可以在你项目的仓库(命令行)中运行tsc -p

在VS Code(编辑器)中,你可以使用⌘⇧B调出一个菜单,该菜单(包含)可以在正常模式和监视模式下运行转换程序(分别对应tsc:buildtsc:watch)。

vs code build tasks menu

了解静态和动态类型

JavaScript附带7种动态类型:

  • Undefined
  • Null
  • Boolean
  • Number
  • String
  • Symbol
  • Object

上面的类型被称为动态类型,因为它们在运行时使用。

TypeScript为JavaScript语言带来了静态类型,并且这些类型在编译时(无需运行代码)被确定。静态类型可以预测动态类型的值,这可以帮助在无需运行代码的情况下警告你可能出现的错误。

基本静态类型

好吧,我们来深入研究下TypeScript的语法。以下是TypeScript中最常见的类型。

备注:我遗漏了never和object类型,因为根据我的经验,它们并不被经常使用。

boolean

你已经很了解truefalse值了。

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)是由numbernull类型组成的,因此TypeScript只希望numbernull类型的值加入数组。

类型注释

类型推断系统不够用的时,你需要在变量和对象上声明类型。

基本类型

在(上面)基本静态类型章节的介绍中,所有的类型都使用:后跟类型名来声明。

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 aliasinterface的比较的话,我推荐你看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函数的第二个参数是一个字符串,因此创建的数组将其所有元素设置为具有字符串类型。

应该注意的是,按照惯例,单个(大写)字母用于泛型类型(比如:TK)。可是,并不限制你使用更具有描述性的名称来表示你的泛型类型。下面示例就是为所提供的泛型类型使用了更具有描述性的名称:

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)

原文链接 https://www.robertcooper.me/get-started-with-typescript-in-2019

@reng99 reng99 added translation translate somehing blog a single blog labels Feb 17, 2019
@reng99 reng99 added the typescript typescript tag label Apr 21, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blog a single blog translation translate somehing typescript typescript tag
Projects
None yet
Development

No branches or pull requests

1 participant