一、TypeScript
1.基础知识
(类型安全角度)强弱类型:强类型不允许随意的隐式类型转换,而弱类型允许。
(类型检查角度)静态类型和动态类型:静态类型在声明时已明确且类型不可再修改,动态类型在运行阶段才可确定,且可随意改变
var a = 100;
a = 'foo'
console.log(a) //a的类型在运行时才可确定且可以修改
Flow
- 类型注解
为变量、返回值、参数定义相关的类型
let num: number = NAN //指定变量类型,可以存放NAN以及Infinity表示无穷大
let n: null = null //存放null 只能用null类型
let q: void = undefined //存放undefined使用void
let arr: Array<number> = [1,2,3] //存放数组以及指定数组中元素的类型
//或者使用 let arr2: number[] = [1,2,3]
// let arr3: [number,string] = [100, 'foo'] //数组中只能两个元素且元素类型于定义时类型顺序一致
const obj1:{foo: string, bar: number}={foo: 'a', bar:11}//指定对象中的数据类型只能有foo和bar这两个成员
const obj2:{foo?: string, bar: number} = {bar:11} //在成员之后添加?表示可没有该成员
const obj3:{[string]:string} = {} //表示对象的键和值都是string类型
function square(n:number){ //指定传入参数的类型
return n*n
}
function foo():void{} //指定返回值类型
- 函数作为回调函数传入时也可以限制类型
function foo(callback:(string,number) => void ){ //传入的回调函数参数分别是string和number,返回值是空
callback('string',100)
}
- 使用字面量类型限制
const a: 'foo' = 'foo' //限制变量a只能是foo
const type: 'success' | 'warning' | 'danger' = 'success' //限制只能是规定的之一
const s = number | string = 100
- 可以使用type关键词定义一个类型
type StringOrNumber = string | number //定义的类型可以在多处使用
const str:StringOrNumber = '100'
- 使用maybe类型
const b: ?number = undefined
//等同于 const b: number| undefined | void = undefined
- mixed 类型
可以接受任意类型
function passMixed(value: mixed){
if(typeof value === 'string'){ //接受任意类型的参数需要内部明确是何种类型
value.substr(1)
}
if(typeof value === 'number'){
value*value
}
}
- any 类型
可以接受任意类型,但any是弱类型,可以当做数字和字符串都不会在语法上报错。
function passAny(value: any){
value.substr(1)
value*value
}
二、TypeScript
1.作用域
声明的变量是全局作用域,可以设置立即执行函数创建单独的作用域,或者使用exprot导出作用域
(function(){
const a = 123
})()
// 或者
export {}
TypeScript数据类型
如果在定义变量时赋值,则会根据赋值情况隐式类型推断,如果未赋值,则默认定义为any类型
1.任意类型 any
function stringify(value:any){
return JSON.stringify(value)
}
stringify(100)
stringify('100')
2.object类型
包括对象、数组、函数类型
const obj:object = {} //[] //function(){}
//只设置对象类型可使用字面量定义的方式
const foo: {bar:number,a:string} ={bar:123,a:'test'}
3.数组类型
const arr1: Array<number> = [1,2,3]
const arr2: number[] = [1,2,3]
function sum(...arrgs:number[]){ //无需逻辑判断传入的类型
return arrgs.reduce((prev,current)=>prev + current, 0)
}
sum(1,2,4)
4.元组类型
const tulpe: [number, string] = [18, 'zce']
//可以通过解构或者下标值方式获取
const age = tulpe[0]
const [age, name] = tulpe
5. 枚举类型
使用enmu关键字声明枚举类型
enmu post = { //枚举中的成员和属性用等号连接
a = 0, //可以设置为数字也可设置为字符串
b = 1,
c = 2
}
enmu post = { //枚举成员默认会累加,如果给第一个指定了值,之后会依次累加
e = 8,
f,
g
}
const obj = { //对象中的成员和属性值用冒号连接
title: 'a',
code: post.a
}
6. 函数类型
设置参数类型和返回值类型,参数前添加?可设置可选参数,也可给参数添加默认值。用 rest操作符设置任意参数
function func1(a:number,?b:number = 10):string{
return 'func1'
}
func1(1,20)
function func2(a:number,...rest:number[]):string { //可以传入任意参数
return 'func2'
}
const func3 = function(a:number):string{ return 'func3'}
断言
从一个接口中获取到一些数据之后对这些数据加工处理时会使得TypeScript无法确定数据类型报语法错误,则可以使用断言明确数据类型。可以使用as关键词断言;也可以使用<>关键词断言。断言仅在编译时会使用并非类型转换
const nums = [100,200,300,400]
const res = nums.find(i => i>0) //typescript默认未number或者undefined类型,使得无法进行后续乘法运算
const square = res * res
const num1 = res as number //使用as关键词断言res为number类型
const num2 = <number>res //使用<>明确res的数据类型 但是会与JSX命名冲突无法使用
接口
使用interface定义一个接口
interface post{
title: string
content: string
subtitle?: string //设置可选成员
readonly summary: string //readonly设置只读成员
}
function printPost(value:post){ //要求传入的对象必须有title和content成员
console.log(value.title)
console.log(value.content)
}
prontPost({
title: 'JS',
content: 'JS is useful'
summary: 'A js'
})
设置动态成员
interface Cache{
[prop:string]:string
}
const obj:Cache = {}
obj.name = 'value1'
obj.post = 'value2'
类
- 类的定义
class person {
name:string
age: number
constructor(name:string,age:number){
this.name = name
this.age = age
}
}
- 类的访问修饰符
通过public和private定义类的成员,默认为公有,可以在外部访问。protected 可以通过继承在子类中访问的成员
只读修饰符readonly
class Person {
public name: string
privage age: number
protected readonly gender: string //可以在构造函数中初始化也可以在实例中初始化
constructor(name:string,age:number){
this.name = name
this.age = age
this.gender = 'true'
}
}
class Student extends Person {
constructor (name: string, age: number){
super(name,age)
console.log(this.gender) // true 可以在子类中访问
}
}
- 接口
不同的类之间具有相同的属性,但实现方法不同
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)} //实现了两个接口以后必须实现两个接口中的所有方法
}
class Animal implements Eat,Run {
eat(food: string):void {console.log('进食',food)}
run(distance: string): void {console.log('爬行',distance)}
}
- 抽象类
约束子类中必须有某一成员,但抽象类包含具体实现,接口只能是成员的抽象不包含实现。定义时在class之前添加abstract关键词,抽象类只能被继承,不能通过new创建实例对象
abstract class Animal {
eat(food: string):void{console.log('进食',food)}
abstract run(distance: string):void //父类中有抽象方法子类中必须实现基础父类的抽象方法
}
class Dog extend Animal {
run(distance: string){console.log('四角爬行',distance)}
}
const d = new Dog()
d.run('walk')
d.eat('肉')
泛型
声明是不指定具体类型,调用时传递具体类型。为了能够极大复用代码。Array类是一个泛型类
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[]{ //定义泛型数组,在需要指定类型的地方使用<T>表示
const arr = Array<T>(length).fill(value)
return arr
}
const res = createStringrArray(3,'foo') //res=>['foo','foo','foo']
const a = createArray<string>(2,'a') //a => ['a','a'] 在调用时给出具体类型
类型声明
某些第三方库并非TS书写,使用时无法体验强类型,可使用类型声明。兼容普通JS模块
import { cameCase } from 'lodash'
declare function cameCase(input: string):string
const res = cameCase('hello typed')