程序中的异常在运行时才能发现
类型不明确函数功能会发生改变
对对象索引器的错误用法
// : number 叫做类型注解
function sum (a: number, b: number) {
return a + b
}
console.log(sum(1, 2))
先执行yarn init -y
执行yarn add flow-bin
在代码中第一行添加flow注释:// @flow
在函数中形参后面加上冒号和类型:function sum (a: number, b: number)
执行yarn flow init
创建.flowconfig
执行yarn flow
// @flow
// : number 叫做类型注解
function sum (a: number, b: number) {
return a + b
}
console.log(sum(1, 2))
console.log(sum('100', '100'))
flow官方提供的操作:
yarn add flow-remove-types --dev
yarn flow-remove-types src -d dist
使用babel配合flow转换的插件:
yarn add @babel/core @babel/cli @babel/preset-flow --dev
.babelr
文件:
{
"presets": ["@babel/preset-flow"]
}
yarn babel src -d dist
VsCode中的插件:Flow Language Support
/**
* 原始类型
* @flow
*/
const a: string = 'foo'
const b: number = Infinity // NaN // 100
const c: boolean = false // true
const d: null = null
const e: void = undefined
const f: symbol = Symbol()
const arr: Array<number> = [1, 2, 3]
const arr2: number[] = [1, 2, 3]
// 元组
const foo: [string, number] = ['foo', 100]
const obj1: {foo: string, bar: number} = {foo: 'string', bar: 100}
// 问号表示可有可与的属性
const obj2: {foo?: string, bar: number} = {bar: 100}
// 表示当前对象可以添加任意个数的键,不过键值的类型都必须是字符串
const obj3: {[string]: string} = {}
obj3.key1 = 'value1'
// obj3.key2 = 100
function fn (callback: (string, number) => void) {
callback('string', 100)
}
fn(function (str, n) {
})
const fo: 'foo' = 'foo'
// 联合类型,变量的值只能是其中之一
const type: 'success' | 'warning' | 'danger' = 'success'
// 变量类型只能是其中的一种类型
const g: string | number = 100
type StringOrNumber = string | number
const h: StringOrNumber = 'stri' // 100
// maybe类型 加一个问号,变量除了可以接受number类型以外,还可以接受null或undefined
const gender: ?number = null
// 相当于
// const gender: number | null | void = undefined
// Mixed / Any mixed是强类型,any是弱类型,为了兼容老代码,是不安全的,尽量不用any
// string | number | boolean |...
function passMixed (value: mixed) {
}
passMixed('string')
passMixed(100)
function passAny (value: any) {
}
passAny('string')
passAny(100)
const element: HTMLElement | null = document.getElementById('root')
TypeScript:JavaScript的超集/扩展集
yarn add typescript --dev
创建一个扩展名为ts
的文件, myTypeScript.ts
:
// TypeScript 可以完全按照JavaScript 标准语法编码
const hello = (name: string) => {
console.log(`hello, ${name}`)
}
hello('TypeScript')
// hello(111)
执行命令 yarn tsc myTypeScript.ts
, 会生成一个同名的js文件
查看myTypeScript.js
文件:
// TypeScript 可以完全按照JavaScript 标准语法编码
var hello = function (name) {
console.log("hello, " + name);
};
hello('TypeScript');
// hello(111)
tsc:(typescript compiler) 编译ts文件: 执行命令yarn tsc myTypeScript.ts
tsc编译整个项目:
yarn tsc --init
,生成tsconfig.json
文件yarn tsc
, 按照配置文件将src中的ts文件生成到了dist中的js文件,并且是采用ES2015语法const a: string = 'foobar'
const b: number = 100 // NaN Infinity
const c: boolean = true // false
// const d: boolean = null // 严格模式下不支持赋值null
const e: void = undefined // 函数没有返回值时的返回值类型
const f: null = null
const g: undefined = undefined
const h: symbol = Symbol()
标准库就是内置对象所对应的声明
在tsconfig.json中写上:
"lib": ["ES2015", "DOM"],
yarn tsc --locale zh-CN
每个文件都是全局作用域,所以在不同文件中定义同名变量会报错,解决方案:
使用立即执行函数,产生作用域
(function () {
const a = 123
} )()
使用export
const a = 11
export {} // 确保跟其他实例没有成员冲突
TypeScript中的Object类型泛指所有的的非原始类型。如对象、数组、函数.
object类型并不单指对象,而是指除了原始类型之外的其他类型.
对象的赋值必须与定义的属性保持一致,不能多也不能少。更专业的写法是用接口.
export {} // 确保跟其他实例没有成员冲突
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]
function sum (...args: number[]) {
return args.reduce((prev, current) => prev + current, 0)
}
sum(1, 2, 3)
固定长度的数据。 例如Object.entries(obj)的返回值里面的每一个元素都是一个元组
export {}
const tuple: [number, string] = [19, 'jal']
// 下标取值
// const age = tuple[0]
// const name = tuple[1]
// 数组解构
const [age, name] = tuple
// JS中没有枚举类型,则使用对象模拟枚举类型
// const PostStatus = {
// Draft: 0,
// Uppublished: 1,
// Published: 2
// }
// 枚举类型。使用时和对象属性一样
// 如果不指定值,则从0开始累加。如果制定了第一个成员的值,后面的成员则再第一个成员基础上累加。值如果是字符串,就得指定具体的值
const enum PostStatus {
Draft = 0,
Uppublished = 1,
Published = 2
}
const post = {
title: 'Hello TypeScript',
content: 'Type...',
status: PostStatus.Draft
}
// 获取不确定参数
// function func1 (a: number, b: number): string {
// function func1 (a: number, b?: number): string {
// function func1 (a: number, b: number = 10): string {
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 'f'
}
any类型是为了兼容老的代码,它还是动态类型,是不安全的,尽量少用
function stringify (value: any) {
return JSON.stringify(value)
}
stringify('string')
stringify(100)
stringify(true)
let foo: any = 'string'
foo = 100
foo.bar()
let age = 18 // ts推断出类型是number
// age = 'str' // 会报错 不能将类型“"str"”分配给类型“number”。
let foo // 此时无法推断具体类型,foo则是动态类型,any类型
foo = 1 // 不会报错
foo = 'string' // 不会报错
const nums = [110, 120, 119, 112]
const res = nums.find(i => i>0)
// const res: number | undefined
// const square = res * res
const num1 = res as number // 断言 res 是number
const square = num1 * num1
const num2 = <number>res // 或者这种方式。JSX下不能使用
// 可以用分号分割,分号可以省略
interface Post {
title: String
content: String
}
function printPost (post: Post) {
console.log(post.title)
console.log(post.content)
}
printPost({
title: 'hello',
content: 'javascript'
})
可选属性、只读属性
interface Post {
title: String
content: String
subtitle?: string // 可有可无的属性。也就是说该属性为string或者undefined
readonly summary: string
}
const hello: Post = {
title: 'hello',
content: 'javascript',
summary: 'js'
}
//报错: Cannot assign to 'summary' because it is a read-only property.
// hello.summary = '11'
动态属性
interface Cache {
// 动态成员
[prop: string]: string
}
const cache: Cache = {}
cache.foo = 'ff'
TypeScript增强了class的相关语法
类的基本使用
class Person {
// ES2017定义的语法:
name: string // = 'init name'
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
sayHi (msg: string): void {
console.log(`I am ${this.name}`)
}
}
访问修饰符:private public protected 。默认是public.
export {}
class Person {
// ES2017定义的语法:
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}`)
}
}
const tom = new Person('tom', 18)
console.log(tom.name)
// console.log(tom.age) // 属性“age”为私有属性,只能在类“Person”中访问。
// console.log(tom.gender) // 属性“gender”受保护,只能在类“Person”及其子类中访问。
class Student extends Person {
constructor(name: string, age: number) {
super(name, age)
// 父类的protected属性子类可以访问。
console.log(this.gender)
}
}
静态属性、构造器私有化后不能new
class Student extends Person {
private constructor(name: string, age: number) {
super(name, age)
console.log(this.gender)
}
static create(name: string, age: number) {
return new Student(name, age)
}
}
const jack = Student.create('jack', 18)
只读属性,在属性声明前面加上readonly即可
protected readonly gender: boolean
// 尽可能让接口简单。一个接口只约束一个能力,一个类实现多个接口
interface Eat {
eat (foo: string): void
}
interface Run {
run (distance: number): void
}
class Person implements Eat, Run {
eat(food: string): void {
console.log(`优雅的进餐:${food}`)
}
run(distance: number): void {
console.log(`直立行走:${distance}`)
}
}
class Animal implements Eat, Run {
eat(food: string): void {
console.log(`呼噜呼噜的吃:${food}`)
}
run(distance: number): void {
console.log(`爬行:${distance}`)
}
}
被abstract修饰,不能被new,只能被继承。继承抽象类的子类,必须实现父类的抽象方法
abstract class Animal {
eat (food: string) : void {
console.log(`呼噜呼噜的吃:${food}`)
}
// 抽象方法不需要方法体,子类必须要实现抽象方法
abstract run(distance: number): void
}
// 非抽象类“Dog”不会实现继承自“Animal”类的抽象成员“run”
class Dog extends Animal {
run(distance: number): void {
console.log(`四脚爬行:${distance}`)
}
}
const dog = new Dog()
dog.run(20)
dog.eat('fish')
把类型作为参数,放在尖括号中
function createNumberArray(length: number, value: number): number[] {
const arr = Array(length).fill(value)
return arr
}
const res = createNumberArray(3, 100 ) // [100, 100, 100]
function createArray (length: Number, value: T): T[] {
const arr = Array(length).fill(value)
}
const arrRes = createArray(3, 'foo') // ['foo', 'foo', 'foo']
TypeScript中的扩展名为d.ts
的文件就是类型声明文件
import {camelCase} from 'lodash'
// 自己写declare语句声明类型
declare function camelCase (input: string): string
const res = camelCase('zjal')