TypeScript
程序员文章站
2022-07-14 21:04:37
...
TypeScript是JavaScript超集(superset)
TypeScript 安装(npm)
- 安装typescript依赖
这一步安装完成之后其实就可以使用tsc命令来执行TypeScript的相关代码了npm i typescript -D
- 配置tsconfig.json文件
生成的配置文件如下:tsc --init
{ "compilerOptions": { "target": "es5", // 指定ECMAScript目标版本 "lib": ["ES2015", "DOM"], // 使用的类库 "module": "commonjs", // 指定模块化类型 "declaration": true, // 生成 `.d.ts` 文件 "sourceMap": true, // 开启源文件映射 "outDir": "./dist", // 编译后生成的文件目录 "rootDir": "./src", // 源代码所在的文件 "strict": true // 开启严格的类型检测 } }
- 将编译命令添加到package.json中
"scripts": { "build": "tsc" # 增加 ts 编译命令 },
- 运行命令
编译完成之后,我们可以看到目录下出现了dist目录,在该目录下生成了三个文件,一个包含代码逻辑的js文件,一个包含类型定义的interface文件,还有一个包含映射关系的map文件npm run build
原始类型
以上,如果需要使用es6的特性就需要把target改成es2015,但如果这样改的话,那默认的标准库就被覆盖了,所以需要在lib中添加"lib": [“ES2015”, “DOM”], 这样就可以都找到es6和原本dom的标准库了。const a: string = 'foobar' const b: number = 100 // NaN Infinity const c: boolean = true // false // const d: number = null // 关闭严格模式下可以使用 const e: void = undefined const f: null = null; const g: undefined = undefined; const h: symbol = Symbol(); // 如果是定义target:es5则symbol会报错,因为找不到对应类型的标准库,所以要添加"lib": ["ES2015", "DOM"]
标准库就是内置对象所对应的声明中文错误提示
tsc --locale zh-CN
object类型
object类型并不单指普通的对象,可以是数组也可以是函数const foo: object = function () {} // [] // {} const obj: {foo: number, bar: string} = {foo: 123, bar: 'string'}
数组类型
// 数组类型的两种表示方式 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
元组
// 数组中元素的数据类型都一般是相同的(any[] 类型的数组可以不同),如果存储的元素数据类型不同,则需要使用元组。 const tuple: [number, string] = [18, 'zce'] // const age = tuple[0] // const name = tuple[1] const [age, name] = tuple // --------------------- const entries: [string, number][] = Object.entries({ foo: 123, bar: 456 }) const [key, value] = entries[0] // key => foo, value => 123
枚举
// 用对象模拟枚举 // const PostStatus = { // Draft: 0, // Unpublished: 1, // Published: 2 // } // 标准的数字枚举 // 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,则会在编译后的文件中生成一个双向的键值对对象,可以通过值找到键) 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 } // PostStatus[0] // => Draft
函数
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' }
any类型
function stringify (value: any) { return JSON.stringify(value) } stringify('string') stringify(100) stringify(true) let foo: any = 'string' foo = 100 foo.bar() // any 类型是不安全的
隐式类型判断
let age = 18 // number // age = 'string' // 报错,因为ts已经把age推断为number类型 let foo // 这时时any类型,这时,往这个变量中放入任意类型的值都不会报错 foo = 100 foo = 'string' // 建议为每个变量添加明确的类型标注
类型断言(辅助ts更加明确每个变量的类型)
// 假定这个 nums 来自一个明确的接口 const nums = [110, 120, 119, 112] const res = nums.find(i => i > 0) // const square = res * res //报错 const num1 = res as number // 推荐 const num2 = <number>res // JSX 下不能使用,因为尖括号会和jsx里面的标签产生冲突 // 类型断言时编译过程中的概念,当编译过后,这个断言也就不存在了
接口
interface Post { title: string content: string } function printPost (post: Post) { console.log(post.title) console.log(post.content) } printPost({ title: 'Hello TypeScript', content: 'A javascript superset' }) // 接口只是做约束所用的,实际运行过程中并没有实际的意义
接口补充(可选成员,只读成员)
interface Post { title: string content: string subtitle?: string // 可选成员 readonly summary: string // 只读成员 } const hello: Post = { title: 'Hello TypeScript', content: 'A javascript superset', summary: 'A javascript' } // hello.summary = 'other' // 报错 // ---------------------------------- interface Cache { [prop: string]: string // 动态成员 } const cache: Cache = {} cache.foo = 'value1' cache.bar = 'value2'
类的基本使用
描述一类具体事物的抽象特征,表述一类具体对象的抽象成员,typescript增强了class的相关语法class Person { name: string // = 'init name' age: number constructor (name: string, age: number) { this.name = name // 不能直接使用this,需要在类中声明(主要是为了给属性做类型的标注) 在es7标准定义的 this.age = age } sayHi (msg: string): void { console.log(`I am ${this.name}, ${msg}`) } }
类的访问修饰符
class Person { public name: string // = 'init name' private age: number // 私有属性 protected gender: boolean // 受保护的,只有子类可以访问 constructor (name: string, age: number) { this.name = name this.age = age this.gender = true } sayHi (msg: string): void { console.log(`I am ${this.name}, ${msg}`) console.log(this.age) } } class Student extends Person { private constructor (name: string, age: number) { // 设置成private,那么这个类就不能在外部被实例化,也不能被继承 super(name, age) console.log(this.gender) } static create (name: string, age: number) { // 在类的内部创建静态方法,内部去实例化,外部才可以通过静态方法访问这个类 return new Student(name, age) } } const tom = new Person('tom', 18) console.log(tom.name) // console.log(tom.age) // 报错,因为age私有 // console.log(tom.gender) // 报错,只有子类可以访问 const jack = Student.create('jack', 18)
类的只读属性
class Person { public name: string // = 'init name' private age: number // 只读成员 protected readonly gender: boolean // 对于只读属性可以在申明的时候去初始化赋值,也可以在构造函数中赋值,初始化过后就不能再次被修改了 constructor (name: string, age: number) { this.name = name this.age = age this.gender = true } sayHi (msg: string): void { console.log(`I am ${this.name}, ${msg}`) console.log(this.age) } } const tom = new Person('tom', 18) console.log(tom.name) // tom.gender = false
类与接口
interface Eat { eat (food: string): void } interface Run { run (distance: number): void } 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}`) } }
抽象类
抽象类和接口有些类似,也是要约束子类当中必须要有某一个成员,但是不同于接口的是,抽象类当中可以包含一些具体的实现,而接口只能够是成员的抽象,不包含具体的实现。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)
泛型
在定义函数,接口类时,不定义它的类型,等到使用的时候再去定义它的类型,这样可以极大程度的复用代码function createNumberArray (length: number, value: number): number[] { const arr = Array<number>(length).fill(value) return arr } function createStringArray (length: number, value: string): string[] { const arr = Array<string>(length).fill(value) return arr } function createArray<T> (length: number, value: T): T[] { const arr = Array<T>(length).fill(value) return arr } // const res = createNumberArray(3, 100) // res => [100, 100, 100] const res = createArray<string>(3, 'foo') // 泛型就是把在定义时不明确的类型变成一个参数,在使用的时候再去传递这个参数
类型声明
declare 类型声明,一个函数在定义的时候因为一些原因没有被声明,那在使用的时候就需要用declare来声明一下。这种用法时为了兼容npm中一些用js编写的模块declare function camelCase (input: string): string
以上就是TypeScript的笔记啦~~~
上一篇: 2|the summary of web study
下一篇: typeScript
推荐阅读