TypeScript的应用及方法介绍(typescript菜鸟教程)
TypeScript是JavaScript的一种超集是一种强类型语言
原始类型 < Primitive Type >
原始数据类型 const a: string = 'foobar' const b: number = 123 //NaN Infinity const c: boolean = true //false // 在非严格模式(strictNullChecks)下, // string,number,boolean都可以为空 // const d: string = null // const d: number = null // const d: boolean = null const e: void = undefined const f: null = null const g: undefined = undefined // Symbol 是 ES2015 标准中定义的成员 // 使用它的前提是必须确保有对应的 ES2015 标准库的引用 // 也就是 tsconfig.json 中的 lib 选项必须包含 ES2015 const h: symbol = Symbol()复制代码
作用域问题
1.使用立即执行函数
(function(){ const a = 123 })()复制代码
2.export {}
const a = 123 export {}复制代码
Object Types<对象类型>
指的是除原始类型之外的类型,可以使用对象自变量的语法方式
const foo: object = function(){}//[] {} const obj: { foo: number, bar: string } = { foo: 123, bar: 'strinf'} Array Types const arr1: Array<number> = [1, 2, 3] const arr2: number[] = [1, 2, 3] function sum(...args:number[]){ // 判断是不是每个成员都是数字 return args.reduce((prev,current)=>prev+current,0) } sum([1,2,3])//6复制代码
Tuple Types<元组类型>
指的是明确元素类型元素数量的一个数组
const tuple: [number, string] = [24,'shy'] const age = tuple[0] const name = tuple[1] const [age,num] = tuple Object.entries({ foo:123, bar:456 })复制代码
Enum Types <枚举类型>
特点:
1.给一组数值分别取上不同的名字
2.一个枚举中只会存在几个固定的值,并不会出现超出范围的可能性
可以使用object模仿枚举类型 const PostStatus = { Draft: 0, Unpublished: 1, Published: 2 } typeScript中使用enum去定义一个枚举值 enum PostStatus = { Draft = 0, Unpublished = 1, Published = 2 } 如果不设置初始值的话默认从0开始依次赋值 enum PostStatus = { Draft, Unpublished, Published } 如果枚举值是字符串,需要设置初始值 enum PostStatus = { Draft = 'aaa', Unpublished = 'bbb', Published = 'ccc' }复制代码
枚举类型会入侵到运行时候的代码(会影响编译后的结果)
以枚举为数字类型为例 转译为js文件时
var PostStatus; (function (PostStatus){ PostStatus[PostStatus['Draft'] = 0] = 'Draft' PostStatus[PostStatus['Unpublished'] = 1] = 'Unpublished' PostStatus[PostStatus['Published'] = 2] = 'Published' })(PostStatus||(PostStatus={})) 使用常量枚举就会解决这个问题(在enum前加上const) const enum PostStatus = { Draft, Unpublished, Published }复制代码
Function Types<函数类型>
声明型函数类型限制 function func1(a: number,b: number): string{ return 'funct1' } 调用是必须传入两个number类型的值,少或多都会造成异常 当传入参数为可选参数时可以使用?的形式,但需要注意可选参数要放在最后 function func1(a: number,b?: number): string{ return 'funct1' } 也可以使用给参数设置默认值 function func1(a: number,b: number = 10): string{ return 'funct1' } 使用任意个数参数 function func1(...rest: number[]): string{ return 'funct1' } 函数表达式类型限制 const func2:(a: number,b: number = 10) => string = function(a: number,b: number): string{ return 'funct2' }复制代码
Any Types<任意类型>
不会进行类型检查,所以类型是不安全的
function stringify(value){ return JSON.stringify(value) } stringify('string') stringify(123) stringify(true) let foo: any = 'string' foo = 100复制代码
Type Inference<隐式类型推断>
根据变量的使用情况推断类型
let age = 18 //number age = 'string' //age会报语法错误 当不设置初始值时,默认类型为any 建议为每个变量添加明确的类型,便于维护,理解复制代码
Type assertions<类型断言>
明确知道类型时
//假定这个nums来自一个明确的接口 const nums = [100,120,1320,130] const res = nums.find(i=>i>0) const square = res * res //res为number||undefined 在这种情况下我们需要明确res为number类型复制代码
使用类型断言的两种方式
1.as const num1 = res as number 2.<number> const num2 = <number>res //JSX 下不能使用,会和标签冲突 类型断言(代码在编辑阶段的概念)不是类型转换(代码在运行阶段的概念)复制代码
Interfaces<接口>
一种规范,一种约定
interface Post{ title: string; //结尾可以使用,;或不写 contet: string; } function printPost(post: Post) { console.log(post.title) console.log(post.contet) } printPost({ title: 'Hello TypeScript', content: 'A JavaSctipt superset' })复制代码
总结:接口就是用来约束对象结构,一个对象要实现接口,他就必须要拥有接口中约束的所有成员
可选成员 interface Post{ title: string; //结尾可以使用,;或不写 contet: string; subTitle?: string //使用?表示为可选成员 } 只读成员 interface Post{ title: string; //结尾可以使用,;或不写 contet: string; readonly summary: string//只读成员,不能修改 } 动态成员 interface Cache{ [key: string]: string //成员键与值都为字符串类型 } const cache: Cache = {} cache.foo = 'value1' cache.bar = 'value2'复制代码
Classes<类>
描述一类具体事物的抽象特征
class Person { name: string age: number constructor(name: string, age: number){ this.name = name this.age = age } sayHi(msg:string):void{ console.log(`I am ${this.name},${msg}`) } } private私有属性,只能内部访问 class Person { name: string private age: number constructor(name: string, age: number){ this.name = name this.age = age } sayHi(msg:string):void{ console.log(`I am ${this.name},${msg}`) console.log(this.age) } } const tom = new Person('tom',18) 只能访问到tom.name,不能访问到tom.age public公有属性,默认就是public protected 也是私有属性,只允许在子类中显示 class Person { name: string 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{ constructor(name: string, age: number){ super(name,age) console.log(this.gender) } }复制代码
接口:约束子类当中必须拥有某个成员(只是接口的抽象,不包含实现)
interface Eat{ eat(food: string): void //只做接口约定不做接口实现 } interface Run{ run(distance: string): void //一个接口约束一个能力,一个类型实现多个接口 } class Person implements Eat,Run { eat(food: string): void { console.log(`${food}`) } run(distance: string): void { console.log(`${distance}`) } }复制代码
抽象类
抽象类:约束子类当中必须拥有某个成员(包含接口实现)
abstract class Animal { eat(food: string): void { console.log(`${food}`) } abstract run(distance: string): void { console.log(`${distance}`) } } 只能继承不能new创建 class Dog extends Animal{ run(distance: string): void { console.log(`${distance}`) } } const d = new Dog() d.eat('肉') d.run('跑')复制代码
泛型
在定义函数接口或类时没有指定具体类型,在使用时再去指定类型的特征
function createArray<T> (length: number, value: T):T { const arr = Array<T>(length).fill(value) return arr } const res = createArray<string>(3,'str')//['str','str','str'] const res2 = createArray<number>(3,100)//[100,100,100]复制代码
TypeScript的优缺点
优点
增强了代码的可读性和可维护性
包容性,js可以直接改成ts,ts编译报错也可以生成js文件,兼容第三方库,即使不是ts编写的
社区活跃,完全支持es6
缺点
增加学习成本
增加开发成本,因为增加了类型定义
需要编译,类型检查会增加编译时长,语法和类型系统复杂的话时间特别特别长
eval和new Function()这种操作类型系统管不到
和有些库结合时不是很完美
作者:菜市场小石
链接:https://juejin.cn/post/7039337621364932621