TypeScript是拥有类型的JavaScript超集,它可以编译成普通、干净、完整的JavaScript代码
TypeScript的编译环境
`ts-> js -> 浏览器运行`
1. 安装 npm install typescript -g
2. 查看版本 tsc -v
3. tsc '跟当前ts文件进行编译'
`搭建ts环境的两种方案`
1. 通过webpack搭建一个ts环境
npm install ts-loader typescript -D
'webpack.config.js配置'
module: {
rules: [
{
test: '/\.ts$/',
loader: 'ts-loader'
}
]
}
`tsc --init` -> 生成tsconfig.json文件
2. 通过安装'npm install ts-node -g' ts-node TypeScript.ts 编译->运行在node上面
还要依赖两个包, npm install tslib @types/node -g
变量的声明
1. '声明类型后ts会进行类型检测,声明的类型可以称之为类型注解'
`格式 var/let/const 标识符:数据类型 = 赋值`
const name: string = 'coder'
var age: number = 12
let height: number = 1.99
2. 'string和String的区别'
// string : ts中的字符串类型
// String : js中的字符串包装类的类型
3. '类型推导/推断'
let foo = 'foo'
// foo此时就是字符串类型
基本数据类型
1. '数字类型 number'
// 整数型,和浮点型统称为数字类型
let num: number = 123
num = 222
let num1: number = 100 // 十进制
let num2: number = 0b100 // 二进制
let num3: number = 0o105 // 八进制
let num4: number = 0x100abf // 十六进制
2. '布尔类型 boolean 取值true或者false'
let flag: boolean = true
flag = false
3. '字符串类型 string'
let message = 'hello world'
let message1 = `name: ${name}`
4. '数组类型 Array'
const names1 = Array<string> = ['abc'] // 不推荐(react jsx中有冲突 <div><div>)
const names2 = string[] = ['abc', 'cdb'] // 推荐
names1.push('sth')
5. '对象类型 Object'
// 会自动推导出里面值的类型
const info = {
name: 'why',
age: 18
}
6. 'null类型 值只能null'
const n1: null = null
7. 'undefined类型 值只能undefined'
let n2: undefined = undefined
8. 'Symbol类型'
const title1 = Symbol('title')
const title2 = Symbol('title')
const info = {
[title1]: '处女是'
[title2]: '老老师'
}
info[title1]
ts的数据类型
1. 'any类型 任意类型'
// 无法确定变量类型,并且可能它会发生一些变化,可以使用any类型
// 不想给js添加具体的数据类型时可以使用any
// any 类型可以赋值给任意类型
let message: any = 'hello world'
message = 123
message = true
message = {}
2. 'unknown类型'
// 描述类型不确定的变量
// unknown类型只能赋值给any和unknown类型
function foo() { return 'abc' }
function bar() { return 123 }
let flag:boolean = true
let result: unknown
if(flag) {
result = foo()
} else {
result = bar()
}
3. 'void类型'
// 当一个函数没有返回值的时候就是void类型,或者加上ovid类型
function foo(num1: number, num2: number):ovid {
return null 或者 undefined // 当加上ovid类型,可以返回null或者undefined
}
foo(10,20)
4. 'never类型'
// 永远不会发生值的类型
function foo(): never {
while(true) {
// 死循环,永远没有返回值
}
}
function bar(): never {
throw new Error()
}
5. '元组类型 tuple'
// 多种元素的组合
const info: [string, number, number] = ['bac', 18, 18.9]
6. '函数的数据类型 '
// 给参数添加类型注解和 (num: number)
// 返回值加类型注解 () : number
// 在开发中,通常情况可以不写返回值类型(自动推导)
function sum(num1: number, num2: number): number {
return num1 + num2
}
`匿名函数的参数类型`
const names = ['abc', 'sfc', 'sdaf']
// item根据上下文的环境推导出来的,可以不加类型注解
// 上下文中的函数:可以不添加类型注解
names.forEach(function(item) => {})
7. '对象类型'
// point: x/y -> 对象类型
// {x: number, y: number}
function printPoint(point: {x: number, y: number}) {
console.log(point.x, point.y)
}
printPoint({x: 123, y: 321})
8. '可选类型'
// point: x/y/z -> 对象类型
// {x: number, y: number, z?: number}
function printPoint(point: {x: number, y: number, z?: number}) {
console.log(point.x, point.y)
}
printPoint({x: 123, y: 321})
printPoint({x: 123, y: 321, z: 2143})
9. '联合类型 union type'
// ts的类型系统允许我们使用多种运算符,从现有的类型中构建新类型
// number|string
function printID(id: number | string) {
console.log(id)
}
printID(123)
printID('ads')
10. '类型别名 type alias'
type IDType = string | number | boolean
type PointType = {
x: number
y: number
z: number
}
function printId(id: IDType) {}
function printId(id: PointType) {}
11. '类型断言 as'
// ts无法获取具体类型信息,这时就需要类型断言
// 关键字 as 将宽泛的类型,转换成具体的类型
const el = document.getElementById('hty') as HTMLImageElement
el.src = 'url地址'
12. '非空类型断言'
// 关键字 ! 一定有值
function fo(message?: string) {
cosole.log(message!.length)
}
fo()
fo('1324')
13. '可选链 es11新特性'
// 关键字 ?.
// 当对象属性不存在时,会短路,直接返回undefined,如果存在,那么会继续执行
type person {
name: string,
friend?: {
name: string
}
}
const info : person = {
name: 'wht',
friend: {
name: 'kobe'
}
}
console.log(info.friend?.name) // 没有就取的是undefined
14 '!! 和 ?? 运算符'
// !! 操作符 将其他类型转成boolean类型
// ?? 操作符 当操作符左侧是null 或者 undefined时,返回其右侧操作数,否则返回左侧
{}
15. '字面量类型'
// 'Hello World' 也可以作为类型,叫字面量类型
const message: 'Hello World' = 'Hello World'
let align: 'left' | 'right' | 'height' = 'left'
align = 'right'
16. '字面量推理'
const info = {
url: 'http: 4300',
method: 'GET'
}
function request(url: string, method: 'GET' | 'POST') {}
request(info.url, info.method)
// 这是因为我们的对象再进行字面量推理的时候,info其实是一个{url: string, method: string),所以我们没办法将一个string赋值给一个字面量类型。
`解决方法1`
request(info.url, info.method as "GET")
`解决方法2`
const info = {
url: 'http: 4300',
method: 'GET'
} as const
17. '类型缩小'
// typeof padding === 'number' 的判断语句在执行路径中,缩小声明更小的类型,称为缩小
`常见类型保护`
typeof
等平缩小 === !==
instanceof
in
`例子`
type IDType = number | string
function PrintID(id: IDType) {
if(typeof id === 'string') {}
if()
}
18. '函数类型'
`在作为参数时, () => void`
function bar (fn: () => void) {
fn()
}
bar(foo)
`定义常量时,编写函数的类型`
type AddFnType = (num1: number, num2: number) => number
const add: AddFnType = (a1: number, a2: number) => {
return a1 + a2
}
19. '对this类型的处理'
type ThisType = { name: string }
function eating(this: ThisType) {
console.log(this.name + '123')
}
const info = {
name: 'why',
eating: eating
}
info.eating()
eating.call({name: 'kobe'})
eating.apply({name: 'james'})
20. '函数的重载'
`函数的重载: 函数名称相同,但是参数不同的几个函数,就是函数的重载`
// 重载函数
function add(num1: number, num2: number): number
function add(num1: string, num2: string): string
// 实现函数
function add(num1: any, num2: any): any {
return num1 + num2
}
// 先去匹配声明的函数,然后在到函数的实现里去执行函数体
const result = add(10, 290)
const result = add('曾环','酒仙')
// 在函数的重载中,实现函数是不能直接被调用的
add({name: 'why'}, {age: 18}) // 报错
面向对象--类
1. `类的定义`
'关键字 class申明类'
'new 实例化类'
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
eating() {
console.log(this.name + "eating")
}
}
const P = new Person('智能化', 12)
2. `类的继承`
'关键字 extends 继承父类的属性和方法'
'关键字 super 调用父类的构造器constructor'
// 父类
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
eating() {
console.log('eating')
}
}
// 子类
class Student extends Person {
sno: number
constructor(name: string, age: number, sno: number) {
super(name, age)
this.sno = sno
}
// 子类对父类方法的重写
eating() {
// 使用super可以调用父类的方法执行一次
super.eating()
}
studying() {
console.log('studying')
}
}
const stu = new Student('why', 18, 111)
3. `类的多态`
'父类引用指向子类对象'
class Animal {
action() {
console.log('123')
}
}
class Dag extends Animal {
action() {
console.log('234')
}
}
class Fish extends Animal {
action() {
console.log('234')
}
}
// 多态的目的是为了写出更加具备通用性的代码
function make(animals: Animal[]) { // Animal[]父类类型,指向子类对象new Dag()
animals.forEach(animal => { // 所以执行的是子类的方法,这就是多态
animals.action()
})
}
make([new Dag(), new Fish()])
4. `TS中类的成员修饰符`
'public 修饰的是任何地方可见,公有的属性和方法,默认编写的属性就是public'
'private 修饰的是仅在同一类中可见,私有的属性和方法'
'protected 修饰的是仅在类自身及子类中可见,受保护的属性和方法'
class Person {
private name: string = ''
getName(name) {
// private只能在类内部访问,外部不能访问
return this.name = name
}
}
class Person {
protected name: string = ''
}
class Student extends Person {
getName() {
// protected可以在类内部和子类中访问,外部不能访问
return this.name
}
}
5. `只读属性 readonly`
'只读属性是可以在构造器中赋值,赋值后就不可以修改了'
'属性本身是不能修改,但是如果它是对象类型,对象中的属性是可以修改的'
class Person {
readonly name: string
constructor(name: string) {
this.name = name
}
}
const p = new Person()
p.name = 'sdf' // 这里是不能修改的
6. `getter和setter`
class Person {
private _name: string
constructor(_name: string) {
this._name = name
}
// 访问器
set name(newName) {
this._name = newName
}
get name() {
return this._name
}
}
const p = new Person('why')
p.name = '123'
console.log(p.name) // 可以直接访问
7. `类的静态成员`
'不需要new 实例,可以直接访问的成员'
class Student {
static time: string = "10:10"
static attendClass() {
}
}
console.log(Student.time)
8. `抽象类abstract`
'继承是多态使用的前提'
'所以在定义很多通用的调用接口时,我们通常会让调用者传入父类,通过多态来实现更加灵活的调用方式。'
'但是,父类本身可能并不需要对某些方法进行具体的实现,所以父类中定义的方法。,我们可以定义为抽象方法。'
// 抽象类不能被实例化
// 抽象方法可以没有函数体,必须要被子类实现,否则该类必须是一个抽象类
abstract class Shape {
abstract getArea()
}
class Rectangle extends Shape {
private width: number
private height: number
constructor(width: number, height: number) {
super()
this.width = width
this.height = height
}
getArea() {
return this.width * this.height
}
}
9. `类的类型`
class Person {
name: string = '123'
eating() {}
}
const p = new Person() // p类的类型就是Person类
const P1: Person = {
name: 'why',
eating() {}
}
// 使用
function PrintPerson(p: Person) {
console.log(p.name)
}
printPerson(new Person())
printPerson({ name: 'kobe', eating: function() {}})
接口
1. `接口的声明`
'关键字 interface'
// 声明对象类型,和type声明差不多
// 在接口名字前面加一个 I 命名规范
// 在接口可以定义可以定义可选类型
// 也可以定义只读属性
interface InfoType {
readonly name: string
age: number
friend?: {
name: string
}
}
const info: InfoType = {
name: 'why',
age: 18
}
2. `索引类型`
// 通过interface来定义索引类型
interface IndexLanguage {
[index: number] : string
}
const fronLanguage: IndexLanguage = {
0: 'HTML',
1: 'css',
2: 'javascript'
}
interface ILanguageYear {
[name: string] : number
}
3. `函数类型`
// 可调用的接口
interface CalcFn {
(n1: number, n2: number): number
}
4. `接口的继承`
interface ISwim {
swimming: () => void
}
interface IFly {
flying: () => void
}
interface IAction extends ISwim, IFly {}
const action: IAction = {
swimming() {},
flying() {}
}
5. `交叉类型`
interface ISwim {
swimming: () => void
}
interface IFly {
flying: () => void
}
type MyType1 = ISwim | IFly
type MyType2 = ISwim & IFly
const obj1: MyType1 = {
flying() {}
swimming() {}
}
6. `接口的实现`
interface ISwim {
swimming: () => void
}
interface IFat {
eating: () => void
}
// 类实现接口
class Animal {
}
// 继承: 只能实现单个继承
// 实现: 实现接口,类可以实现多个接口
class Fish extends Animal implements ISwim, IEat {
swimming() {}
eating() {}
}
// 编写一个公共的api: 面向接口编程
function swimAction(swimable: ISwim) {
swimable.swimming()
}
// 所有实现了接口的类对应的对象,都可以传入
swimAction(new Fish())
swimAction({swimming: function() {}})
interface和type的区别
`我们会发现interface和type都可以用来定义对象类型,那么在开发中定义对象类型时,到底选择哪一个呢?`
1. 如果是定义非对象类型,通常推荐使用type,比如Direction、Alignment、一些Function ;`如果是定义对象类型,那么他们是有区别的`:
1.interface可以重复的对某个接口来定义属性和方法;
2.而type定义的是别名,别名是不能重复的;
补充字面量赋值
interface IPerson = {
name: string
age: number
}
const info {
name: 'why',
age: 18,
address: '关东'
}
// 是可用通过类型检测的,会先把多余的擦除进行类型检测,
const p: IPerson = info
枚举类型
`枚举其实就是将一组可能出现的值,一个个列举出来,定义在一个类型中,这个类型就是枚举类型;`
`枚举允许开发者定义一组命名常量,常量可以是数空、字符串类型:`
1. `枚举类型的使用`
'关键字 enum'
enum Direction {
LEFT,
RIGHT,
TOP,
HEIGHT
}
function turnDirection(directon: Direction) {
switch(directon) {
case Direction.LEFT
console.log('向左')
break
}
}
turnDirection(Direction.LEFT)
2. `枚举类型的值`
enum Direction {
LEFT = 100,
RIGHT = 200,
}
泛型
`泛型就是类型参数化`
1. `使用泛型`
function sum<Type>(num1: Type, num2: Type): Type {
return
}
sum<number>(10,20)
sum<string>('10','20')
2. `泛型接口的使用`
interface IPerson<T1, T2=string> {
name: T1,
age: T2
}
const p: IPerson<number, number> {
name: 'why',
age: 18
}
3. `泛型类的使用`
class Point<T> {
x: T
y: T
z: T
constructor(x: T, y: T, z: T) {
this.x = x
this.y = y
this.z = z
}
}
const p1 = new Point('2','22','33')
const p2 = new Point<string>('2','22','33')
const p3: Point<string> = new Point('2','22','33')
4. `泛型的类型约束`
'通过extends进行约束'
interface Ilength {
length: number
}
function getLength<T extends ILength>(arg: T) {
return arg.length
}
.d.ts文件配置
`声明模块`
declare module 'loadsh' {
export function join(arr: any[]): void
}
`声明变量/函数/类`
declare let whyName: string
declare let whyAge: number
declare function whyFoo(): void
declare class Person {
name: string
age: number
}
`声明文件`
declare module '*.jpg'
declare module '*.svg'
`声明命名空间`
// 这里相当于全局的
declare namespace $ {
export function ajax(settings: any): any
}