内容概要
- 强类型与弱类型
- 静态类型与动态类型
- JavaScript 自有类型系统的问题, 弱类型、动态类型语言
- Flow静态类型检查方案
- TypeScript语言规范与基本应用
类型系统
- 强类型与弱类型(类型安全)
- 强类型:语言层面限制函数的实参类型必须与形参类型相同
- 弱类型:弱类型语言层面不会限制实参的类型
- 区别
- 强类型有更强的类型约束,而弱类型中几乎没有什么约束
- 强类型语言中不允许任意的隐式类型转换,而弱类型语言则允许任意的数据隐式类型转换
- 强类型优势
- 错误更早暴露
- 代码更智能,编码更准确
- 重构更牢靠
- 减少不必要的类型判断
- 静态类型与动态类型(类型检查)
- 静态类型:一个变量声明时他的类型就是明确的,声明过后,他的类型就不允许再修改
- 动态类型:运行阶段才能够明确变量类型,而且变量的类型随时可以改变
- 动态类型的语言中,变量是没有类型的,变量中存放的值是有类型的
js 没有编译环节, 所以设计成强类型语言也没有什么意义
缺点:大规模应用下,这种「优势」就能变成了短板
TypeScript
JavaScript的超集(superset)
- 任何一种javaScript运行环境都支持
- 功能更为强大,生态也更为健全、更完善
- TypeScript —- 前端领域中的第二语言
- 缺点
- 语言本身多了很多概念
- TypeScript属于渐进式
- 项目初期,TypeScript会增加一些成本
数据类型
原始数据类型
const a: string = "foobar"
const b: number = 100
const c: boolean = true // false
const e: void = undefined
const f: null = null
const g: undefined = undefined
const h: symbol = Symbol()
标准库就是内置对象所对应的声明
Object类型
并不是单纯指object类型,而是指所有的非原始数据类型
- 对象
- 数组
- 函数 ```typescript const foo: object = // function() // [] // {}
// 限制对象类型 const obj: {} = {}
const obj: { foo: number, bar: string } = { foo: 123, bar: “string” }
<a name="DajsZ"></a>
### 数组类型
```typescript
const arr:Array<number> = [1, 2, 3]
const arr1: number[] = [1, 2, 3]
---------------------------
function sum( ...args: number[]) {
// 判断是不是每个成员都是数字
return args.reduce((prev,current) => prev + current, 0)
}
sum(1, 2, 3)
// sum(1, 2, 3, "4") // 报错
元组类型
const tuple: [number, string] = [18, 'zce']
// const age = tuple[0]
// const name = tulpe[1]
const [age, name] = tuple
// ------------
Object.entries({
foo: 123,
bar: 456
})
枚举类型 (enum)
const PostStatus = {
Draft: 0,
Unpublished: 1
Published: 2
}
const enum PostStatus {
Draft = 0,
Unpublished = 1
Published = 2
}
const post = {
title: "hello typeScript",
content: "typeScript is a typed support of javaScript",
status: PostStatus.Draft // 0 , 1, 2
}
函数类型 (Function Types)
function func1 (a, b) {
return "func1"
}
// ts:
// 传入参数个数 为2 类型为number 返回值 string
function func1 (a: number. b: number) : string {
return "func1"
}
// 传入参数个数 为1 或2, 第二个形参可以不传 类型为number 返回值 string
function func1 (a: number. b?: number) : string {
return "func1"
}
或者:
function func1 (a: number. b: number = 10) : string {
return "func1"
}
// 接收任意个数的参数 ...rest
function func1 (a: number. b: number = 10, ...rest: number[]) : string {
return "func1"
}
// 箭头函数的方式:
const func2: (a: number, b: number) => string = {
return "func2"
}
任意类型 (Any Types)
function stringify(value: any) {
return JSON.stringify(value)
}
// 轻易不要使用any
隐式类型推断
let age = 18 // number
age = "string" // 会报错
类型断言
const nums = [110, 120, 119, 112]
const res = nums.find(i => i > 0)
// 断言
// 类型断言不是类型转换
const num1 = res as number;
const num2 = <numebr>res
接口 interface
接口就是用来约束对象的结构,一个对象去实现一个接口, 必须去拥有这个接口当中所约束的所有成员
// 定义接口、
interface Post {
title: string
content: string
}
function printPost(post: Post) {
console.log(post.title)
console.log(post.content)
subtitle?: string // 可选成员
readonly summary: string // 只读成员
}
// 即约束函数的参数必须是对象,且有title和content两个key值
printPost({
title: "dsffd",
content: 'sdfsdfdf'
})
// 动态成员
interface Cache {
[prop: string]: string
}
const cache: Cache = {}
cache.foo = "v1"
cache.bar = "v2"
类
描述一类具体事物的抽象特征
- es5:函数 + 原型 模拟实现类
- es6:s6开始javaScript中有个专门的class
- typeScript 增强了 class 的相关语法
- 访问修饰符
- private 私有属性 、只允许父类中使用
- public 共有成员,默认
- protected 受保护属性、只允许子类中使用
只读属性
- readonly ```typescript class Person { name: string private age: number protected gender: boolean protected readonly dontchange: boolean // 子类和父类都不允许修改
constructor (name: string, age: number) { this.name = name this.age = age }
sayHi (msg: string): void{ console.log(
I am ${this.name}, ${msg}
) } }
const tom = new Person(‘tom’, 18) console.log(tom.name) console.log(tom.age) // 访问不到 console.log(tom.gender) // 访问不到, 只允许在子类中访问的
- 类与接口
- implements
```typescript
interface EatAndRun {
eat(food: string): void
run(distance: string): void
}
class Person implements EatAndRun {
eat(food: string): void {
console(`优雅的进餐 ${food}`)
}
run(distance: number) {
console(`直立行走 ${distance}`)
}
}
class Animal implements EatAndRun {
eat(food: string): void {
console(`呼噜呼噜的吃 ${food}`)
}
run(distance: number) {
console(`爬行 ${distance}`)
}
}
// 改进:
interface Eat {
eat(food: string): void
}
interface Run {
run(distance: string): void
}
class Person implements Eat,Run {
eat(food: string): void {
console(`优雅的进餐 ${food}`)
}
run(distance: number) {
console(`直立行走 ${distance}`)
}
}
- 抽象类
- class 关键词前面添加 abstract
- 被定义为抽象类之后 只能被继承, 不能够再使用new的方式去创建实例了
- 父类中有抽象方法时,子类就必须去实现这个方法
``typescript abstract class Animal { eat (food: string): void { console.log(
呼噜呼噜的吃${food}`) } // 定义抽象方法,子类继承的时候也必须定义该方法 abstract run (distance: number): void }
class Dog extends Animal {
run(distance: number) {
console(四脚爬行 ${distance}
)
}
}
const dog = new Dog() dog.eat(‘阿西吧’) dog.run(100)
<a name="K93bf"></a>
### 泛型
- 定义函数接口或类的时候没有去指定具体的类型, 等到使用的时候再去指定具体类型的
```typescript
function creatNumberArray (length: number, value: number): number[] {
const arr = Array<number>(length).fill(value)
return arr
}
function creatNumberString (length: number, value: string): string[] {
const arr = Array<string>(length).fill(value)
return arr
}
const res = creatNumberArray(3, 100)
// [100, 100, 100]
const res = creatNumberString(3, 'foo')
// ['foo', 'foo', 'foo']
// 使用泛型
function creatArray (length: number, value: T): T[] {
const arr = Array<T>(length).fill(value)
return arr
}
const res = creatArray<string>(3, 'foo')
// ['foo', 'foo', 'foo']
const res = creatArray<number>(3, 'foo')
// [100, 100, 100]
类型声明
引入第三方库时候
- 可以去安装对应库的类型声明模块
- 也可以的时候用 declare ```typescript import { camelCase } from ‘lodash’
declare function camelCase (input: string): string
const res = camelCase(‘hello typed’)
```