1. 什么是 TypeScript
TypeScript 是一种由微软开发的自由和开源的编程语言。它是基于 JavaScript 的一门语言,是 JavaScript 的一个超集。也就是说 TypeScript 在 JavaScript 上多了一些扩展的特性,包括新的类型系统以及对 ES6+ 新特性的支持。 TypeScript 最终也编译为 JavaScript ,所以在任何支持 JavaScript 的运行环境中, 都可以使用 TypeScript 进行开发。
2. 快速上手 TypeScript
2.1 获取 TypeScript
使用 yarn 安装命令行的 TypeScript 编译器
//为了方便管理,我选择项目内安装 TypeScript
$ yarn install typescript --dev
2.2 编译 TypeScript 文件
// xxx 代表需要编译的 ts 文件,便已完成后在项目目录里会生成 xxx.js 文件
$ tsc xxx.ts
2.3 TypeScript 配置文件
//执行完毕后,项目下会多出一个 tsconfig.json
$ yarn tsc --init
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation 是否启用增量编译*/
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "dist", /* Redirect output structure to the directory. */
"rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
}
2.4 按配置编译 ts 文件为 js 文件
//上述配置会编译 src 目录下的 ts 文件,并自动在 dist 目录下生成编译后的js文件,以及 .map 文件
$ yarn tsc --init
3. TypeScript 原始类型
TypeScript 原始类型的声明方式与 Flow 基本一致,区别是 Flow 生命时必须赋值,TypeScript 中初始化时可以不赋值。
//Number 类型
const a: number = 10;
//String 类型
const b: string = "semliker";
//Boolean 类型
const c: boolean = false;
//undefined 类型
const d:undefined = undefined
//null 类型
const e:null = null
//void 类型
const f: void = undefined;
//Symbol 类型
const g = Symbol();
//BigInt 类型
//我们在使用 BigInt 的时候,必须添加 ESNext 的编译辅助库,如下:
const h: bigint = 9007199254740991n
const i: bigint = BigInt(9007199254740991)
const j: bigint = BigInt("9007199254740991")
4. TypeScript 其他类型
4.1 Object 类型
// object 类型是指除了原始类型以外的其它类型
const foo: object = function () {} // [] // {}
// 如果需要明确限制对象类型,则应该使用这种类型对象字面量的语法,或者是「接口」
const obj: { foo: number, bar: string } = { foo: 123, bar: 'string' }
4.2 Array 类型
// 数组类型的两种表示方式
const arr1: Array<number> = [1, 2, 3]
const arr2: number[] = [1, 2, 3]
// 案例 -----------------------
// 如果是 JS,需要判断是不是每个成员都是数字
// 使用 TS,类型有保障,不用添加类型判断
function sum (...args: number[]) {
return args.reduce((prev, current) => prev + current, 0)
}
sum(1, 2, 3) // => 6
4.3 元组(Tuple) 类型
const tuple: [number, string] = [18, 'zce']
//写法1
const age = tuple[0]
const name = tuple[1]
//写法2
const [age, name] = tuple
// ---------------------
const entries: [string, number][] = Object.entries({
foo: 123,
bar: 456
})
const [key, value] = entries[0]
4.4 枚举(Enum) 类型
// 用对象模拟枚举
// const PostStatus = {
// Draft: 0,
// Unpublished: 1,
// Published: 2
// }
// 标准的数字枚举,数字可省略,会自动从 0 开始自增
enum PostStatus {
Draft = 0,
Unpublished = 1,
Published = 2
}
// 数字枚举,枚举值自动基于前一个值自增
enum PostStatus {
Draft = 6,
Unpublished, // => 7
Published // => 8
}
// 字符串枚举
enum PostStatus {
Draft = 'aaa',
Unpublished = 'bbb',
Published = 'ccc'
}
// 常量枚举,不会侵入编译结果,编译后会直接赋值常量
const enum PostStatus {
Draft,
Unpublished,
Published
}
const post = {
title: 'Hello TypeScript',
content: 'TypeScript is a typed superset of JavaScript.',
status: PostStatus.Draft // 3 // 1 // 0
}
4.5 函数类型
// ts 中形参与实参必须一致,可选参数需要在变量后:前加上?
function func1 (a: number, b: number = 10, ...rest: number[]): string {
return 'func1'
}
func1(100, 200)
func1(100)
func1(100, 200, 300)
// -----------------------------------------
//把函数赋值给变量,变量类型定义
const func2: (a: number, b: number) => string = function (a: number, b: number): string {
return 'func2'
}
4.6 任意类型
// any 类型不会做类型检查,是任意类型的
function stringify (value: any) {
return JSON.stringify(value)
}
stringify('string')
stringify(100)
stringify(true)
let foo: any = 'string'
foo = 100
foo.bar()
5. TypeScript 隐式类型推断
// TypeScript 推断 age 为数字类型,赋值为字符串类型会报错
let age = 18 // number
// age = 'string'
// 定义时没有赋值, TypeScript 认为 foo 是一个 any 类型的值
let foo
foo = 100
foo = 'string'
6. TypeScript 类型断言
// 假定这个 arrs 来自一个明确的接口
const nums = [100, 200, 300, 400]
//TypeScript 默认认为 res 的类型为 number 和 undefined,但我们明确知道 res 为数字类型时使用类型断言
const res = nums.find(i => i > 0)
//这时候因为 res 可能会是 undefined 类型,所以这里会报错
// const square = res * res
// 类型断言方法一,使用as
const num1 = res as number
//类型断言方法二,使用<>
// JSX 下不能使用,<>会有冲突
const num2 = <number>res
7. TypeScript 接口
//使用 interface 关键词定义一个 Post 接口
interface Post {
title: string
content: string
subtitle?: string //可选类型,可以选择性实现
readonly summary: string //只读,不可修改
}
//指定传入的 post 变量必须实现接口 Post,拥有 title、content 属性,否则会报错。
function printPost (post: Post) {
console.log(post.title)
console.log(post.content)
}
printPost({
title: 'Hello TypeScript',
content: 'A javascript superset'
})
//任意类型接口,可任意添加
interface Cache {
[prop: string]: string
}
const cache: Cache = {}
cache.foo = 'value1'
cache.bar = 'value2'
8. TypeScript 类
8.1 TypeScript 中的类,直接用 this 去访问类的属性会报错,需要先在类中明确声明类所拥有的属性。
class Person {
name: string // = 'init name'
age: number
constructor (name: string, age: number) {
this.name = name
this.age = age
}
sayHi (msg: string): void {
console.log(`I am ${this.name}, ${msg}`)
}
}
8.2 TypeScript 类的访问修饰符
public name: string // 公有属性,默认的访问修饰符为 public
private age: number //私有属性
protected gender: boolean //受保护的属性,可以在子类中去访问
8.3 TypeScript 类的只读属性
readonly 关键字,如果属性有了访问修饰符,readonly 属性只能加在访问修饰符后。
8.4 类与接口
//创建 Eat 接口
interface Eat {
eat (food: string): void
}
//创建 Run 接口
interface Run {
run (distance: number): void
}
//实现 Eat 和 Run 接口
class Person implements Eat, Run {
eat (food: string): void {
console.log(`优雅的进餐: ${food}`)
}
run (distance: number) {
console.log(`直立行走: ${distance}`)
}
}
class Animal implements Eat, Run {
eat (food: string): void {
console.log(`呼噜呼噜的吃: ${food}`)
}
run (distance: number) {
console.log(`爬行: ${distance}`)
}
}
8.5 抽象类
// abstract 关键字实现一个抽象类,抽象类不能用 new 实现,只可以继承
abstract class Animal {
eat (food: string): void {
console.log(`呼噜呼噜的吃: ${food}`)
}
//实现一个抽象方法,也不会去实现
abstract run (distance: number): void
}
//集成的时候去实现这个抽象类和抽象方法
class Dog extends Animal {
run(distance: number): void {
console.log('四脚爬行', distance)
}
}
const d = new Dog()
d.eat('嗯西马')
d.run(100)
8.6 泛型
// T 表示一个动态类型,让类型定义变成可定义的
function createArray<T> (length: number, value: T): T[] {
const arr = Array<T>(length).fill(value)
return arr
}
const res = createArray<string>(3, 'foo')