typescript笔记
什么是TypeScript?
TypeScript是微软公司开发的一款开源的JavaScript超集语言。
JavaScript超集:当前任何JavaScript都是合法的TypeScript代码。
TypeScript主要为JavaScript提供了类型系统和ES6语法支持。
与Flow相比,Flow是一个类型检查工具,TypeScript是一种开发语言。
TypeSCript有自己的编译器,可以将写好的TypeScript代码最终通过编译器编译成JavaScript代码进行运行。
安装和配置TypeScript
TypeScript最终要运行起来,需要将TypeScript转换成JavaScript代码。转换可以通过TypeScript的命令行工具来完成。
安装:
npm install -g typescript
执行以上命令会在全局环境下安装tsc命令。
编写typescript代码:
示例代码:
新建一个hello.ts的文件
let num: number = 100
num = 1234
function sum(a: number, b: number): number {
return a + b;
}
const total: number = sum(10, 20)
编译:
tsc hello.ts
通过上面这个命令可以将hello.ts文件编译成js文件。
初始化:
tsc --init
使用以上命令可以在当前目录下生成一个tsconfig.json的文件,用来配置当前项目的相关内容。
tsconfig.json
{
"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', 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', or 'react'. */
// "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": "./", /* Redirect output structure to the directory. */
// "rootDir": "./", /* 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. */
/* 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. */
}
}
配置项:
- "outDir": "./dist" : 生成文件的存放目录
- "rootDir": "./src" :ts代码的存放路径
- "strict": true: 将TypeScript代码转换成严格模式的代码
- "target": "es5": 将ts代码转换成js代码的版本(默认是es5)
- "module": "commonjs":将ts代码转换后,使用的模块化标准。(默认commonjs)
数据类型
数值类型(Number)
const a: number = 123 // 数值
const b: number = NaN // 非数字
const c: number = Infinity // 正无穷大的数值
const d: number = 0xA12 // 十六进制
const e: number = 0b1010101 // 二进制
const f: number = 0o75 // 八进制
字符串类型(String)
const str1: string = "hello"
const str2: string = 'hello'
const str3: string = `hello`
布尔类型 (Boolean)
const flag1: boolean = true
const flag2: boolean = false
数组(Array)
const arr1: Array<number> = [1, 2, 3]
const arr2: number[] = [1, 2, 3]
元祖(Tuple)
元祖类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
const arr1: [number, string] = [100, 'hello']
空值(void)
某种程度上来说,void类型像是与any类型相反,它表示没有任何类型,当一个函数没有返回值时,通常会见到返回值类型是void。
声明一个void类型没什么大用。因为它只能赋值为undefined
function foo():void {
alert('hello word')
}
const result: void = undefined
undefined
undefined 类型只能赋值为undefined
null
null类型只能赋值为null
any
any类型可以赋值为任意类型
let val: any = 100
val = 'hello'
val = {}
val = []
Never
never类型表示的是那些用不存在的值的类型。例如, never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。变量也可能是naver类型,当他们被用部位真的类型保护所约束时。
never类型时任何类型的子类型,也可以赋值给任何类型;然而,没有类型时never的子类型或可以赋值给nerver类型(除了never本身之外),即使any也不可以赋值给never。
never类型一般用在不可能返回内容的函数返回值类型
// 返回never的函数必须存在无法到达的终点
function error(message: string): never {
throw new Error(message)
}
// 推断的返回值类型为never
function fail() {
return error('something failed')
}
// 返回never的函数必须存在无法到达的终点
function infiniteLoop(): never {
while (true) { }
}
对象(Object)
const obj1: { name: string, age: number } = { name: 'xiaoming', age: 20 }
枚举(Enum)
enum类型是对JavaScript标准数据类型的一个补充。像C#等其他语言一样,使用枚举类型可以为一组数值赋予友好的名字。
enum Color {
red,
green,
blue,
}
const green: Color = Color.green;
默认情况下从0开始为元素编号,也可以手动的制定成员的数值。例如,我们将上面的例子改成从1开始编号。
enum Color2 {
red = 1,
green,
blue
}
const red: Color2 = Color2.red
或者,全部都采用手动赋值
enum Color3 {
red = 1,
green = 2,
blue = 3
}
const blue: Color3 = Color3.blue
类型断言
有时你会遇到这样的情况,你会比typescript更了解某个值的详细信息,通常这回发生在你清楚地知道一个尸体具有比他现有类型更确切的类型。
通过类型断言这种方式可以告诉编译器,类型断言好比其他语言里的类型转换,但是不进行特殊的数据检查和解构。它没有运行时的影响,只是在表意阶段起作用,typescript会假设你,已经进行了必须的检查。
类型断言有两种形式。其一是尖括号语法。
const someValue: any = 'this is a string'
const strLength: number = (<string>someValue).length
另一个为as语法:
const someValue: any = 'this is a string'
const strLength: number = (someValue as string).length;
两种形式的等价的,只有使用哪个大多数凭个人喜好,然而,当你在typescript里使用jsx时,只有as 语法断言是被允许的。
类
介绍
传统的Javascript程序使用函数和机遇原型的继承来创建可重用的罪案。但对于熟悉使用面向对象方式的程序员来讲就有些棘手。因为他们用的是机遇类型的继承斌切对象是由类构建出来的。从ECMAScript2015,也就是ES6开始,JavaScript程序员将能够使用基于类的面相对象的方式。使用typescript,我们允许开发着现在就使用这些特性。并且编译后的JavaScript可以子所有主流浏览器和平台上运行,而不需要等到下个JavaScript版本。
一个简单的使用例子:
class Greeter {
// 与ES6不同的是,TS中属性必须声明,需要指定类型
greeting: string
// 声明好属性之后,属性必须赋值一个默认值后者在构造函数中进行初始化。
constructor(message: string) {
this.greeting = message;
}
greet() {
return 'htllo' + this.greeting
}
}
let greeter = new Greeter('word')
类的继承
class Say {
name: string
constructor(name: string) {
this.name = name
}
say() {
console.log(this.name + " say good morning")
}
}
class Person extends Say {
}
const john = new Person('john')
john.say()
class Say {
name: string
constructor(name: string) {
this.name = name
}
say() {
console.log(this.name + " say good morning")
}
}
class Person extends Say {
type: string
constructor(type: string, name: string) {
super(name)
this.type = type
}
// 子类中如果出现了和父类同名的方法,则会进行合并覆盖
job() {
console.log(this.name + 'job is ' + this.type)
}
}
const john = new Person('john', '程序员')
john.say()
john.job()
访问修饰符
访问修饰符指的基石可以在类的成员前通过添加关键字来设置当前成员的访问权限
- public: 公开的,默认,所有人都可以进行访问。
- private: 私有的,只能在当前类中进行访问。
- protected: 受保护的,只能在当前类或者子类中进行访问。
enum CarColor {
red = 'red',
green = 'green',
blue = 'blue'
}
class Car {
// 如果不加访问修饰符,则默认是公开的,所有人都可以访问
color: string
constructor() {
this.color = CarColor.red
}
protected go() {
console.log('go to school')
}
}
const BYD = new Car()
BYD.color
class Audi extends Car {
// 添加了private,只能在当前的类中使用
private run() {
this.go() // protected 修饰后在子类可以正常访问
console.log(this.color)
}
}
const audi = new Audi()
audi.color
// 报错; run方法使用了private修饰外面访问不到
// audi.run()
readonly修饰符
使用readonly管检测可以将属性设置为只读的,只读属性必须在声明时或者构造函数里被初始化。
class Person {
readonly name: string;
readonly numberOfStep: number = 8
constructor(theName: string) {
this.name = theName
}
}
const QaQ = new Person('fdsffsdfsf')
QaQ.name = 'fsdfsdfsdfsd' // 报错!name是只读的,不能赋值
参数属性
在上面例子中,我们不得不定义一个受保护的成员name和一个构造函数参数theName在Person类里,并且立即将theName的值赋值给name。这种情况经常会遇到。参数属性可以方便地让我们在一个地方定义并初始化一个成员。下面例子是对之前Animal类的修改版,使用了参数属性。
class Person2 {
constructor(private name: string) { }
move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}`)
}
}
存取器
class People {
private _name: string = ''
// 当访问name属性的时候会自动调用这个方法,返回值为访问此属性获取到的值
get name(): string {
return this._name
}
// 当修改name属性的时候会自动调用这个方法,返回值为修改此属性的值
set name(value: string) {
// 设置器中可以添加相关的校验逻辑
if (value.length < 2 || value.length > 5) {
throw new Error('名称不合法')
}
this._name = value
}
}
let p = new People()
p.name = 'hello word'
接口
TypeScript的核心原则之一是对值所具有的结构进行类型检查,它有时候被称作“鸭式辨型法”或“结构性子类型化”。在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。
一个简单的示例代码:
function printLabel(labelledObj: { label: string }) {
console.log(labelledObj.label)
}
let myObj = { size: 10, label: "size 10 object" }
printLabel(myObj)
类型检查会查看printLabel的调用,printLabel有一个参数,并要求这个对象有一个名为label类型为string的属性。需要注意的是,我们传入的对象参数实际上会包含很多属性。但是编译器只会减产那些必须的属性是否存在,并且其类型是否匹配。然而有些时候TypeScript却并不回这么宽松。例如以下示例
我们重写上面的例子,这次使用接口来描述,必须包含一个label属性且类型为string:
// 使用接口进行声明
interface LabelledValue {
readonly label: string // 在接口中也可以设置只读属性
name?: string // 加上?代表可选属性,可以传也可以不传
success(msg: string): void
[propName: string]: any // 额外的属性检查,如果多传了额外的参数自动忽略掉
}
function printLabel(options: LabelledValue) {
}
printLabel({ label: 'hello word', success() { } })
函数类型接口
interface SumInterface {
(a: number, b: number): number
}
const sum: SumInterface = function (a: number, b: number): number {
return a + b
}
类类型的接口
interface PersonInterface {
name: string
age: number
say(): void
}
class Jack implements PersonInterface {
name: string = 'jack'
age: number = 18
say() { }
}
接口继承接口
interface OneInterface {
x: number,
y: number,
}
interface TwoInterface extends OneInterface {
z: number
}
const Print: TwoInterface = {
x: 10,
y: 20,
z: 30,
}
多继承接口(一次性继承多个接口)
interface OneInterface {
x: number,
y: number,
}
interface TwoInterface extends OneInterface {
z: number
}
interface ThreeInterface extends OneInterface, TwoInterface {
date: Date
}
const Print2: ThreeInterface = {
x: 10,
y: 20,
z: 30,
date: new Date()
}
接口继承类
class Boy {
name: string = ''
say(): void { }
}
interface Say extends Boy {
}
const Even: Boy = {
name: 'Even',
say() { }
}
Even.say()