typeScript基础使用
- 安装yarn add typescript --dev
- 运行yarn tsc ts文件 进行编译转换成js代码
typeScript配置文件
- 使用命令生成配置文件 yarn tsc --init
- 单独编译tsc文件,tsconfig.json不会生效
- 运行yarn tsc
6种原始数据类型在typescript中的基本使用
/**
* 原始数据类型
*/
const a: string = '123'
const b: number = 123//NaN Infinity包括其中
const c: boolean = true//只能存放true 或者false
const d: string = undefined //string、number、boolean可以设置为空值,可以设置null或者undefined,但是在严格模式下是不能进行设置的,默认情况下可以即在tsconfig.json中的"strict": false
const e: void = undefined//函数返回值为空值或者没有函数返回值时,默认情况下只能设置为null或者undefined,但是在严格模式的情况下只能是undefined
const f: null = null
const g: undefined = undefined
const h:symbol=Symbol()//此种类型只能存放symbol的值,在无配置的情况下会报错需要在tsconfig.json中的`lib` 编译器选项更改为 es2015 或更高版本
typescript标准库声明(内置对象所对应的声明)
- 更改标准库方法1
"target": "es5",==>"target": "es2015",
- 更改标准库方法2
"lib": ["es2015","DOM"],//注意设置时需要带上bom和dom的默认设置"DOM"
中文错误消息(让typescript报错显示中文提示)
- 针对命令行中错误消息显示中文,直接通过打包命令yarn tsc --locale zh-CN
- 针对代码中提示错误信息显示中文-在文件/首选项/设置中搜索typescript locale,将第一个中选项中null更换成zh-CN
作用域问题(重复定义变量,导致页面报错)
- 立即执行函数包裹
(function(){
const a=123
})()
- 通export导出的方式
const a=123
export {}
Object类型(对象自变量声明的结构,最好是用接口的方式声明)
// Object类型
export {} //确保跟其他实例中定义的成员冲突
const foo:object=function(){}//可以接受对象{}/数组[]/函数function(){}
const obj:{foo:number,bar:string}={foo:1,bar:'123'}//声明普通对象需要对象自变量方式,赋值的对象类型结构里面必须与后面的对象结构完全一致
数组类型
// 数组类型
// 声明方式方法一:
const arr1: Array<number> = [1, 2, 3]
// 声明方式方法二:
const arr2: number[] = [1, 2, 3]
// 判断传入sum函数中参数必须是数字类型
function sum(...args: number[]) {
return args.reduce((prev, current) => prev + current, 0)
}
sum(1,2,3)
元组类型
// 元组(tuple)
export { }//确保跟其他成员没有成员冲突
const tuple: [number, string] = [123, '123']//元组中的数据类型有几种,数组只能存在相对应的数据
//元组数据可以通过下标的方式进行访问
const age = tuple[0]
const name = tuple[1]
// 通数据结构的方式提取数据
const [age1, name1] = tuple
枚举类型
枚举有两个特点:
- 可以给一组数值分别取一个很好理解的名字
- 一个枚举中只能存在几个固定的值,不会存在超出范围
// 枚举(enum)
export { }//确保跟其他示例没有成员冲突
// 枚举,枚举的使用和对象的使用一样,直接通过PostStatus.Draft方式使用
enum PostStatus {
// 具体的枚举值
Draft = 0,
Unpublished = 1,
Public = 2
}
// 枚举特殊(数值会自增长-累加):枚举中的值可以不用等号指定,则默认枚举中的值会从零开始进行累加,如果指定枚举中的第一个值,后面的值没有指定,则会从第一个值进行累加
enum PostStatus1 {
// 具体的枚举值
Draft,//Draft=6
Unpublished,
Public
}
const post = {
title: 'hello TypeScript',
content: 'TypeScript is a typed superset of Javascript',
status: PostStatus.Draft
}
枚举类型会入侵运行时的代码(影响编译后的结果),会编译成双向键值对象(可以键获取值,也可以通过值获取键)
enum PostStatus1 {
// 具体的枚举值
Draft,//Draft=6
Unpublished,
Public
}
// 可以使用索引的方式获取枚举的名称
PostStatus1[0]//Draft
如果确定代码中不会使用索引的方式获取枚举名称,就使用常量枚举
// 如果确定代码中不会使用索引的方式获取枚举名称,就使用常量枚举
const enum PostStatus2 {
// 具体的枚举值
Draft,//Draft=6
Unpublished,
Public
}
函数类型
- 函数声明
- 函数表达式
// 函数类型
export { } //确保跟其他示例没有成员冲突
// 函数声明
function func1(a: number, b: number): string {
return 'func1'
}
func1(100, 200)//必须确保形参和实参的个数保持一致
// 函数声明中的可选参数和参数默认值(注意可选参数后参数默认值必须在所有的参数最后面)
//第一种即在参数后加个问号
function func2(a: number, b?: number): string {
return 'func1'
}
func2(100)//在调用时可传可以不传
//第二种直接在参数后加默认值
function func3(a: number, b: number = 10): string {
return 'func1'
}
func3(100)
// 任意参数
function func4(a: number, b: number = 10, ...rest: number[]): string {
return 'func1'
}
func4(100)
// 函数表达式(fun5是接收值,所以也需要进行值的声明)
const fun5: (a: number, b: number) => string = function (a: number, b: number): string {
return 'fun5'
}
任意类型(any)typescript不会对any类型进行类型检查,所以导致any类型不安全
// 任意类型(弱类型)
export {} //确保跟其他示例中没有成员冲突
function stringify(value:any){
return JSON.stringify(value)
}
stringify('string')
stringify(100)
stringify(true)
// 声明any类型后可以值进行任意赋值操作
let foo:any='string'
foo=100
foo.bar()
隐式类型推断(在声明时,直接进行赋值操作,就会推断成相应的类型)
//隐式类型推断
export { }//确保跟其他示例没有成员冲突
// 在声明时,直接进行赋值操作,就会推断成相应的类型
let age = 18//此处会将age变量隐式推断为number类型,在后面进行再次赋值时,只能赋值为数字类型
let string//此处会将string变量隐式推断为any类型,在后面进行再次赋值时,可以赋值为任意类型
string = 123
string = '123'
string = true
类型断言(代码在运行时,typescript无法确定变量的值是什么类型,但开发者知道最后的变量的值是什么类型,此时就需要进行断言)
- 通过as关键词断言
- 在变量前面使用<>(尖括号)方式断言
// 类型断言
const nums = [110, 120, 119, 112]
const res = nums.find(i => i > 0)//typescript无法确定变量的值是什么类型,const res:number|undefined(typescript会提示两种类型)
// 第一种方式断言——as(推荐)
const nums1 = res as number
// 第二种方式断言——<>
const num2 = <number>res//在react的jsx中不能使用,会导致语法冲突
接口(为了约束一个对象的结构,一个对象要实现一个接口,则必须拥有接口中所有成员)
- 接口的基本使用
export { }
interface Post {//实现接口类型的关键字interface
title: string
content: string
}
function printPost(post: Post) {
console.log(post.title)
console.log(post.content)
}
- 接口可选成员、只读成员、动态成员
export { }
interface Post {
title: string
content: string
subtitle?: string//可选成员
readonly summary: string//只读成员,声明后值就不能进行更改
}
function printPost(post: Post) {
console.log(post.title)
console.log(post.content)
}
// 动态成员
interface Cache {
// prop可以用任何的值进行代替 [key:string]:string
[prop: string]: string//[]中指定动态成员的键的类型,外面指的是值的类型
}
const cache: Cache = {}//声明后可以在cache中动态添加成员,但是成员的值类型必须是字符串
cache.foo = 'value'
类class
- 类的基本使用
// 类 class
export { }
class Person {
// 类的属性必须有个初始值
name: string//可以直接赋值 name:string='123'
age: number
constructor(name: string, age: number) {//在typescript中必须明确声明类的中所用的属性,不能动态通过this进行添加
this.name = name
this.age = age
}
sayhi(msg: string): void {
console.log(`I am ${this.name},${msg}`)
}
}
- 类的访问修饰符
- 在属性前加访问修饰符
- public关键字会默认加在属性之前,表示公共的
- private关键词表示属性是类的私有属性,只能在类内部访问,无法在外部直接访问
- protected关键词表示受保护的,只允许在子类中进行访问,无法在外部直接访问
- 构造函数(constructor)访问修饰符
- private关键词表示是类的私有的构造函数,只能在类的内部使用构造函数即实例化(通过static静态属性抛出),无法在外面进行实例化
- protected关键词只能在字类的中进行构造函数,无法在外面直接使用
// 类的访问修饰符
class Person1 {
// public关键字会默认加在属性之前,表示公共的
public name: string
private age: number//在age前加private关键词,则age是Person1的私有属性,只能在类的内部访问
protected gender: boolean //protected关键词,表示受保护的,在外部也无法访问,只允许在子类中进行访问
constructor(name: string, age: number) {//在typescript中必须明确声明类的中所用的属性,不能动态通过this进行添加
this.name = name
this.age = age
this.gender = true
}
sayhi(msg: string): void {
console.log(`I am ${this.name},${msg}`)
}
}
const tom = new Person1('123', 123)
//console.log(tom.age)此时age无法在外部进行访问
//console.log(tom.gender)此时age无法在外部进行访问
class Student extends Person1 {
constructor(name: string, age: number) {
super(name, age)
console.log(this.gender)//可以在子类中访问到父类中gender的属性
}
}
// 构造函数(constructor)的访问修饰符private
class Student1 extends Person1 {
// private关键字会将Student1构造函数无法在外面进行实例化
private constructor(name: string, age: number) {
super(name, age)
console.log(this.gender)//可以在子类中访问到父类中gender的属性
}
// 只能通过static在类的内部进行构造函数,在再外面使用
static create(name: string, age: number) {
return new Student1(name, age)
}
}
const tom1 = Student1.create('name', 12)
// 构造函数的访问修饰符protected,只能在字类的中进行构造函数,无法在外面直接使用
- 类的只读属性 readonly 如果类的属性之前有访问修饰符则直接在修饰符后面加上readonly(protected readonly gender: boolean)
类与接口(将不同的类与类之间的共同特征,通过接口进行抽象)
// 类与接口
export { }
// 通过接口对公共的部分进行约束
interface EatAndRun {
eat(food: string): void
run(distance: number): void
}
class Person implements EatAndRun {
eat(food: string): void {
console.log(`优雅的进餐${food}`)
}
run(distance: number) {
console.log(`站立行走:${distance}`)
}
}
class Animal implements EatAndRun {
eat(food: string): void {
console.log(`呼噜呼噜${food}`)
}
run(distance: number) {
console.log(`爬:${distance}`)
}
}
// 让一个接口约束多个公共部分,就是将以前写在一起的接口进行拆分
interface eat {
eat(food: string): void
}
interface run {
run(distance: number): void
}
class Person1 implements eat,run {
eat(food: string): void {
console.log(`优雅的进餐${food}`)
}
run(distance: number) {
console.log(`站立行走:${distance}`)
}
}
class Animal1 implements eat,run {
eat(food: string): void {
console.log(`呼噜呼噜${food}`)
}
run(distance: number) {
console.log(`爬:${distance}`)
}
}
抽象类(abstract)
- 如果类被定义成抽象类后,只能被继承,不能通过new的方式创建实例对象了,必须通过子类继承
- 抽象类中也可以定义抽象方法(在方法前加abstract),抽象方法不需要方法体,如果父类中存在抽象方法,则在子类中必须存在对应的方法实现
// 抽象类
abstract class name {
eat(food: string): void {
console.log(food)
}
// 抽象方法
abstract food(food1: string): void
}
class name1 extends name {
// 父类的抽象方法必须在子类中实现
food(food1: string): void {
console.log('1111')
}
}
const Name = new name1()
Name.eat('dx')
泛型(generics)
在定义函数、接口、类的时候没有指定具体的类型,在使用时才进行指定(主要是为了复用代码)
// 泛型
export { }
// 创建一个生成数字类型的数组
function NumberArr(length: number, value: number): number[] {
// Array对象创建的使用any类的数组,所以需要Array创建的数组类型,通过泛型参数指定类型<>
const arr = Array<number>(length).fill(value)
return arr
}
// 创建一个生成字符串类型的数组
function StringArr(length: number, value: string): string[] {
// Array对象创建的使用any类的数组,所以需要Array创建的数组类型,通过泛型参数指定类型<>
const arr = Array<string>(length).fill(value)
return arr
}
// 由于上面的函数只能生成当个类型的数组,所以可以通过泛型,将类型转换成参数进行传递,泛型的参数用大写的T,将函数内容中不明确的类型用T进行代表
function creatArr<T>(length: number, value: T): T[] {
const arr = Array<T>(length).fill(value)
return arr
}
const res = creatArr<number>(3, 3)
类型声明(type declaration)
由于第三方的npm模块,而npm的模块不一定是用typeScript进行编写,导致提供的成员不会有强类型的体验(例如:lodash)
// 类型声明
export { }
// 导入lodash
import { camelCase } from 'lodash'
//如果安装的第三方插件没有类型声明的文件,可以通declare进行类型指定
// declare function camelCase(input: string): string
const res = camelCase('hello')