TS
// 全局安装命令
npm install typescript -g
// 查看版本
tsc --version
方式一:通过webpack,配置本地的TypeScript编译环境和开启一个本地服务,可以直接运行在浏览器上;
方式二:通过ts-node库,为TypeScript的运行提供执行环境;
使用ts-node
//安装ts-node
npm install ts-node -g
//另外ts-node需要依赖 tslib 和 @types/node 两个包:
npm install tslib @types/node -g
//现在,我们可以直接通过 ts-node 来运行TypeScript的代码:
ts-node math.ts
使用webpack
// 安装webpack webpack-cli
npm install webpack webpack-cli -D //package.json中"build": "webpack"
// 安装ts-loader typescript
npm install ts-loader typescript -D
// 安装tsconfig.json
tsc init
// 安装webpack-dev-server搭建本地服务
npm i webpack-dev-server -D //package.json中"serve": "webpack serve"
// tslint校验
npm install tslint -g
变量的类型推导
let foo = '123'
foo = 123 // 报错 因为foo赋值的是字符串所以推导到foo只能用字符串类型
TS类型运用
// number
let num: number = 100
let num1: number = 0b100
let num2: number = 0o456
let num3: number = 0x234
console.log(num, num1, num2, num3)
// boolean
let flag: boolean = true
flag = false
flag = 20 > 40
console.log(flag)
// string
let str: string = 'hello World'
str = '123'
// 数组
const names: Array<string> = ['123', 'hello'] // 不推荐 (react jsx中冲突)
const names1: string[] = ['123', 'hello'] // 推荐
// 对象 能推导直接推导
// const info: object = {
// name: 'aaa',
// age: 20
// }
// symbol
// @ts-ignore
const s1: symbol = Symbol('title')
// @ts-ignore
const s2: symbol = Symbol('title')
// null undefined
let n1: null = null // 只能赋值给null
let u1: undefined = undefined // 只能是undefined
// any 可以赋值给任意类型
let anyStr: any = 123
anyStr = '123'
console.log(anyStr)
let anyArray: any[] = [1,'233']
console.log(anyArray)
// unknow 只能赋值给any和unknown类型
let unknownStr: unknown = 123
unknownStr = '123'
console.log(unknownStr)
// let message: string = unknownStr // 报错只能赋值给any和unknown类型
// void类型
function sum(num1: number, num2: number):void {
console.log(num1 + num2)
}
// never类型 永远不会返回结果
function handleMessage() : never {
while (true) {
console.log('1111')
}
}
// tuple元组类型
const tuple1: [string, number, number] = ['why', 18, 1.88]
console.log(tuple1)
const tuple2: (string | number | boolean)[] = ['mov', 20]
console.log(tuple2)
const name = tuple2[0]
// 函数参数是对象类型
// 可选类型 ?
// 联合类型 |
function printPoint(point: {x: number, y?: string | number}) {
console.log(point.x)
console.log(point.y)
}
printPoint({x: 123})
// 可选类型
function printPoint1(point: {x: number, y?: string | number}) {
console.log(point.x)
console.log(point.y)
}
//相当于
function printPoint2(point: {x: number, y: string | number | undefined}) {
console.log(point.x)
console.log(point.y)
}
// 类型别名
type Point = {
x: number,
y: number
}
type message = string | number | boolean
function printPoint3(point: Point) {
console.log(point.x)
console.log(point.y)
}
function printID(id: message) {
}
// 类型断言as 转化为更具体的类型或者更广泛的类型
const el = document.getElementById('my-img') as HTMLImageElement
el.src = ''
class Person {
}
class Student extends Person {
constructor() {
super();
}
studying() {
}
}
function sayHello(p: Person) {
(p as Student).studying()
}
const stu = new Student()
sayHello(stu)
类型缩小
type TypeId = number | string
function printId(id: TypeId) {
if (typeof id === 'number') {
console.log(id)
} else {
console.log(id.toUpperCase())
}
}
// in
type Fish = {
swim: () => void
}
type Dog = {
run: () => void
}
function walk(animal: Fish | Dog) {
if ('swim' in animal) {
} else {
}
}
const fish: Fish = {
swim: function () {
console.log('swimming')
}
}
walk(fish)
函数类型
function foo(num1: number, num2: number) {
}
// 函数类型
type Foo = (num1: number, num2: number) => void
function bar(fn: Foo) {
fn(20, 30)
}
bar(foo)
// 字面量定义
type addType = (num1: number, num2: number) => number
const add: addType = (num1: number, num2: number) => {
return num1 + num2
}
// 如果是元组
const arr: number[] = [1, 2]
const tuple1: [string, (num1: number, num2: number) => void] = ['hello', function bar(num1, num2) {
}]
// 函数剩余参数
function restParamter(...nums: number[]) {
console.log(nums)
}
restParamter(123, 222)
// this的类型
// 当this的类型不明确的时候,ts需要明确指定this的类型
type thisType = {
name: string
}
function eating(this: thisType) {
console.log(this.name, 'name')
}
const info = {
name: 'why',
eating: eating
}
info.eating()
eating.call({name: 'Kobe'})
函数的重载
// 函数的重载:函数名称相同,但是函数参数不同(参数个数不同,参数类型不同)的几个函数就是函数的重载
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, 20)
console.log(result)
联合声明和重载
// 联合声明
// function getLength(args: string | any[]) {
// return args.length
// }
//
// console.log(getLength('asfadsfds'));
// 函数重载
function getLength(args: string): number
function getLength(args: any[]): number
function getLength(args:any):any {
return args.length
}
console.log(getLength([1, 2, 3, 4]));
console.log(getLength('1w123123'));
类的使用
// 类的基础使用
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
}
studying() {
console.log('student studying')
}
eating() {
super.eating();
console.log('student studying')
}
}
const stu = new Student('why', 20, 100)
stu.eating()
// 类修饰符
// public 修饰的是在任何地方可见、公有的属性或方法,默认编写的属性就是public的;
// private 修饰的是仅在同一类中可见、私有的属性或方法;
// protected 修饰的是仅在类自身及子类中可见、受保护的属性或方法;
class Person {
protected name: string = 'why'
getName() {
return this.name
}
}
class Student extends Person {
getName() {
return this.name
}
}
const stu = new Student()
const p = new Person()
console.log(p.getName());
// console.log(stu.getName())
readonly修饰符
// readonly修饰符
// 1.只读属性可以在构造器中赋值,但是不能被修改
// 2.属性本身不能被修改,但是如果属性是对象的话,对象中的属性是可以被修改的
class Person {
readonly name: string
readonly friend?: Person
constructor(name:string, friend?:Person) {
this.name = name
}
}
const p = new Person('why', new Person('Kobe'))
console.log(p)
访问器
class Person {
private _name: string
static age: number = 1234
constructor(name: string) {
this._name = name
}
get name() {
return this._name
}
set name(newName) {
this._name = newName
}
static addStudent() {
console.log('addStudent')
}
}
const p = new Person('why')
console.log(p.name);
p.name = '123'
console.log(p.name)
console.log(Person.age);
Person.addStudent()
抽象类
// 继承是多态的前提
// 因为new Shape中getArea没有实现,所以需要使用抽象类
// 抽象类中的方法可以不需要实现,但是子类中必须实现
// 所以在定义很多通用的调用接口时, // 我们通常会让调用者传入父类,通过多态来实现更加灵活的调用方式。
// 但是,父类本身可能并不需要对某些方法进行具体的实现,所以父类中定义的方法,// ,我们可以定义为抽象方法。
// 什么是 抽象方法? 在TypeScript中没有具体实现的方法(没有方法体),就是抽象方法。
// 抽象方法,必须存在于抽象类中;
// 抽象类是使用abstract声明的类;
// 抽象类有如下的特点:
// 抽象类是不能被实例的话(也就是不能通过new创建)
// 抽象方法必须被子类实现,否则该类必须是一个抽象类;
abstract class Shape {
abstract getArea():number
}
class Rectangle extends Shape {
private readonly width: number
private readonly height: number
constructor(width: number, height: number) {
super();
this.width = width
this.height = height
}
getArea() {
return this.width * this.height
}
}
class Circle extends Shape {
private readonly r: number
constructor(r: number) {
super();
this.r = r
}
getArea() {
return Math.PI * (this.r ** 2)
}
}
// 多态:不同的类型调用同一个方法,表现不同就是多态
function makeArea(shape:Shape) {
return shape.getArea()
}
console.log(makeArea(new Rectangle(10, 20)));
console.log(makeArea(new Circle(10)));
类的类型
// 把一个类当做类型
class Person {
name:string = 'why'
eat: () => void
}
const p: Person = {
name: 'why',
eat: () => {
console.log('eat')
}
}
接口类型
type info = {
name: string,
age: number
}
interface IInfo {
readonly name?:string,
age: number,
getName?: () => void
}
const obj:IInfo = {
name: 'why',
age: 20
}
obj.age = 3
索引类型和函数类型
// 索引类型
interface IIndexPosition {
[index: number]: string
}
const indexType: IIndexPosition = {
0: 'jAVA',
1: 'HTML',
2: 'CSS'
}
console.log(indexType)
// 函数类型
// type Fn = (num1: number, num2: number) => number
interface ICalc {
(num1: number, num2: number): number
}
function foo(num1: number, num2: number, calc: ICalc) {
return calc(num1, num2)
}
console.log(foo(10, 20, (num1, num2) => {
return num1 + num2
}));
export {}
接口继承和交叉类型
// type Fn = () => any
// 接口继承
interface ISwim {
swim: () => void
}
interface IFly {
fly: () => void
}
interface IAction extends ISwim, IFly {
play: () => void
}
// 支持多继承
const actions: IAction = {
play: () => {
},
swim: () => {
},
fly: function () {
}
}
//交叉类型
interface IColor {
color: string
}
interface IFn {
run: () => void
}
// 交叉类型
type MyType = IColor | IFn
type IntertSect = IColor & IFn
const obj: IntertSect = {
color: 'red',
run: () => {
}
}
interface和type的区别
// interface 可以重复的对某个接口来定义属性和方法;
// 而type定义的是别名,别名是不能重复的;
接口的实现
interface ISwim {
swim: () => void,
name:string
}
interface IFly {
fly: () => void
}
// 类是单继承的
// 类可以实现多个接口
class Animal {
}
class Fish extends Animal implements ISwim, IFly {
name:string
constructor(name) {
super();
this.name = name
}
swim() {
}
fly() {
}
}
class Dog implements ISwim {
name: string = '123'
swim() {
}
}
function swimAction(swim: ISwim) {
swim.swim()
}
swimAction({
swim: () => {
console.log('游泳')
},
name: '123'
})
freshness的擦除操作
interface IPerson {
name: string,
age: number,
height: number
}
// 进行对象引用赋值的时候会进行freshness擦除操作
// 将多余的属性擦除后再和接口进行类型判断是否符合类型条件
const info = {
name: 'why',
age: 18,
height: 1.88,
address: '杭州市'
}
const p: IPerson = info
枚举类型的使用
// 枚举类型就是一组常量
enum Direction {
LEFT,
RIGHT,
TOP,
BOTTOM
}
let d: Direction = 12
console.log(d)
function turnDirection(direction: Direction) {
switch (direction) {
case Direction.LEFT:
console.log('转向左边')
break
case Direction.RIGHT:
console.log('转向右边')
break
case Direction.BOTTOM:
break
case Direction.TOP:
break
default:
const foo: never = direction
break
}
}
泛型的基本使用
// 泛型的基本使用
// 参数类型化
function foo<T>(num1: T) {
return num1
}
console.log(foo<object>({name: 'why'}));
// 泛型可以接收多个类型
function bar<T, E>(num1: T, num2: E) {
console.log(num1, num2)
}
bar<number, string>(123, 'abc')
泛型接口的使用
// 泛型接口的使用
interface IPerson<T1, T2> {
name:T1,
age: T2,
getName?: () => void
}
const p:IPerson<string, number> = {
name: 'why',
age: 123
}
// 泛型类的使用
class Person<T, E> {
name:T
age: E
constructor(name: T, age: E) {
this.name = name
this.age = age
}
}
const p1 = new Person<string, number>('why', 10)
// 泛型的类型约束
interface ILength {
length: number
}
function getLength<T extends ILength>(arg: T) {
return arg.length
}
getLength('123')
外部声明和自定义声明
//方式一:在自己库中进行类型声明(编写.d.ts文件),比如axios
//方式二:通过社区的一个公有库DefinitelyTyped存放类型声明文件 //该库的GitHub地址:https://github.com/DefinitelyTyped/DefinitelyTyped/
//该库查找声明安装方式的地址:https://www.typescriptlang.org/dt/search?search=
// 否则自己写声明 lodash.d.ts
//声明模块的语法: declare module '模块名' {}。
//在声明模块的内部,我们可以通过 export 导出对应库的类、函数等;
declare module 'lodash' {
export function join(args: any[]):void
}
// 声明变量
declare let name: string
declare let age: number
declare let height: number
declare function whyoo():void
declare class Person {
name:string
number: number
constructor(name:string, age: number)
}
// 声明文件
declare module '*.jpg'
declare module '*.svg'
declare module '*.jpeg'
declare module '*.png'
declare module '*.gif'
declare module '*.vue' {
}