基础语法
TypeScript的定义
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
- JavaScript的超集 、静态类型
- 需要把ts编译成 JavaScript 代码才能执行
// js动态类型
let a = 123;
a = '123';
// ts静态类型 报错提示
let b1 = 123;
let b2:number = 123;
// ts直接执行
// Uncaught SyntaxError: Unexpected identifier
TypeScript的优势
- 编写时的错误检查
- 编辑器的语法提示
- 代码语义更清晰易懂
interface Point { x: number, y: number }
function tsDemo(data: Point) {
return Math.sqrt(data.x ** 2 + data.y ** 2);
}
tsDemo({ x: 1, y: 123 });
TypeScript运行环境
- node环境 (node -v && npm -v检查版本)
- vs code设置(quote: single && tab: 2)
- 安装prettier (format on save = true && prettier: Single Quote)
- 安装typescript (npm install typescript@3.6.4 -g)
// 验证
tsc demo.ts
node demo.js
// tsc : 无法加载文件 C:\Users\Caffrey\AppData\Roaming\npm\tsc.ps1。
// 未对文件 C:\Users\Caffrey\AppData\Roaming\npm\tsc.ps1 进行数字签名。无法在当前
// 系统上运行该脚本。有关运行脚本和设置执行策略的详细信息,请参阅 https:/go.microsoft.com/
// fwlink/?LinkID=135170中的 about_Execution_Policies。
// 所在位置 行:1 字符: 1
// + tsc demo.ts
// + ~~~
// + CategoryInfo : SecurityError: (:) [],PSSecurityException
// + FullyQualifiedErrorId : UnauthorizedAccess
需要管理员身份打开powershell
运行Set-ExecutionPolicy RemoteSigned
改进
- 安装ts-node (npm install -g ts-node // npm install -g ts-node@8.4.1)
ts-node demo.ts
静态类型
- 变量会受到静态类型的限制(类型不能修改)
- 拥有类型的属性和方法(编辑器的提醒)
基础类型和对象类型
静态类型帮助判断变量的属性和方法是什么
静态类型:
- 基础类型
- 对象类型
// 基础类型 null, undefined, symbol, boolean, void, string, number...
const count: number = 123;
const teacherName: string = 'Dell';
// 对象类型(函数类型, 数组类型...)
class Person {}
const teacher: {
name: string;
age: number;
} = {
name: 'Dell',
age: 18
};
// 数组类型
const numbers: number[] = [1, 2, 3];
// dell 必须是一个Person类对应的对象
const dell: Person = new Person();
// getTotal是一个函数()=> ,返回值是数字 number
const getTotal: () => number = () => {
return 123;
};
类型注解和类型推断
- type annotation: 类型注解, 我们来告诉 TS 变量是什么类型
- type inference: 类型推断, TS 会自动的去尝试分析变量的类型
- 如果 TS 能够自动分析变量类型,我们就什么也不需要做了
- 如果 TS 无法分析变量类型的话,我们就需要使用类型注解
// 可自动分析
const firstNumber = 1;
const secondNumber = 2;
const total = firstNumber + secondNumber;
// 类型注解,结果类型推断
function getTotalData(firstNumber: number, secondNumber: number) {
return firstNumber + secondNumber;
}
const totalData = getTotalData(1, 3);
函数相关类型
- 如果函数的参数解构,对应的参数类型声明 :{ key: value }
// function add(first: number, second: number): number {
// return first + second;
// }
// function sayHello(): void {
// console.log('hello');
// }
// function errorEmitter(): never {
// while(true) {}
// }
function add({ first, second }: { first: number; second: number }): number {
return first + second;
}
function getNumber({ first }: { first: number }) {
return first;
}
const total = add({ first: 1, second: 2 });
const count = getNumber({ first: 1 });
回顾
- 声明函数的两种方式(:类型 = 实现)
// 定义函数结构体,可以把 (str: string) => number 提取出来声明为type(类型别名)
const func1: (str: string) => number = str => {
return parseInt(str, 10);
};
// 直接定义函数参数和返回值的类型
const func = (str: string):number => {
return parseInt(str, 10);
};
- 函数的返回值通常可以通过类型推断返回
// 无法通过类型推断的case
interface Person {
name: 'string';
}
const rawData = '{"name": "dell"}';
const newData: Person = JSON.parse(rawData);
- 联合类型:多种类型声明 ( | )
let temp: number | string = 123;
temp = '456';
数组和元组
数组
- 基础的数组声明
const numberArr: number[] = [1,2,3];
const undefinedArr: undefined[] = [undefined];
- 包含多种类型值的数组声明
const arr: (number | string)[] = [1, '2', 3];
- 通过范型定义包含多种类型值的数组
const arr: Array<number | string | object> = ["jkl", {}, 123];
- 对象数组
// 对象数组中必须包含一个string类型的name,只能有一个key,并且是name
const objectArr: {name: string}[] = [{name: 'caffrey'}]
// 多个key的对象数组
const objectArr: {name: string,age: number}[] = [{name: 'caffrey', age: 24}]
- 类型别名 type alias
type User = {name: string, age:number};
const objectArr: User[] = [{
name: 'caffrey';
age: 24
}]
// typescript这种也支持
class Teacher {
name: string;
age: number
}
const teacherArr: Teacher[] = [
new Teacher(),
{
name: 'caffrey';
age: 24
}
]
元组
元组在数组的基础上还定义了数组每一项的类型限制
- 数组长度固定
- 数组每一项的类型固定
const teacherInfo: [string, string, number] = ['Dell', 'male', 18];
// csv应用
const teacherList: [string, string, number][] = [['dell', 'male', 19], ['sun', 'female', 26], ['jeny', 'female', 38]];
Interface
通用性的类型集合
- interface 接口
const getPersonName1 = (person: {name: string}) => {
console.log(person.name)
}
const setPersonName = (person:{name: string},name: string) => {
person.name = name
}
// interface Person定义
interface Person {
name: string
}
const getPersonName = (person: Person):void => {
console.log(person.name)
}
const setPersonName = (person:Person,name: string):void => {
person.name = name
}
type 类型别名(=)
type Person = {
name: string
}
// interface可以代表函数和对象
// type还可以代表基础类型
type Person1 = string;
- 一般用interface代表类型可以实现,否则才用type
可选择属性(?)
interface Person {
name: string;
age?: number;
}
只读属性readonly
interface Person {
readonly name: string;
}
// 报错,read-only的属性只读,不能被赋值
const setPersonName = (person: Person,name: string):void {
person.name = name
}
字面量强校验
// Person要求传入的参数必须有name
interface Person {
name: string;
age?: number;
}
const getPersonName = (person: Person):void => {
console.log(person.name)
}
// success
const person = {
name: 'caffrey',
sex: 'male'
}
getPersonName(person)
// error (Object literal may only specify known properties, and 'sex' does not exist in type 'Person')
// person写成字面量形式传递给函数报错
getPersonName({
name: 'caffrey',
sex: 'male'
})
当以对象字面量的形式传递时typescript会变成强校验
以缓存的变量形式,只要满足interface的要求即可(name)
[propName: string]: any
interface Person {
name: string;
age?: number;
[propName: string]: any;
}
如果要让字面量形式也满足需求
可以用如上形式代表,还有可能存在string类型的key,任何类型的value的属性
方法
interface Person {
name: string;
age?: number;
[propName: string]: any;
say(): string;
}
const getPersonName = (person: Person): void => {
console.log(person.name);
};
const person = {
name: 'dell',
sex: 'male',
say() {
return 'say hello';
}
};
getPersonName(person);
类应用接口(implements)
class User implements Person {
name = 'dell';
say() {
return 'hello';
}
}
// User类必须要有name属性和say方法
接口的继承(extends)
interface Teacher extends Person {
teach():string
}
// Tercher接口除了要求Person的属性方法,还需要有一个teach方法
const person:Teacher = {
name: 'dell',
sex: 'male',
say() {
return 'say hello';
},
teach() {
return 'teach';
}
};
接口定义函数
interface SayHi {
(word: string): string
}
// 接口使用
const say:SayHi =(word:string)=> {
return word
}
接口编译成javascript
// 初始化typescript工程(配置文件)
tsc --init
// 编译
tsc demo.ts
接口是在typescript开发时定义的代码,完成类型检查的功能
编译成JavaScript的过程中会被剔除
类的定义与继承
- 定义类的属性和方法
class Person {
name: 'caffrey';
getName(){
return this.name;
}
}
const person = new Person();
console.log(person.getName())
- 类的继承(extends)
class Teacher extends Person {
getTeacherName () {
return 'teacher name'
}
}
const teacher = new Teacher()
- 类的重写(子类可以重写父类)
class Teacher extends Person {
getTeacherName () {
return 'teacher name'
}
getName () {
return 'go'
}
}
const teacher = new Teacher()
teacher.getName() === 'go'
- super(代表父类)
当类方法被重写,可以使用super去调用父类的方法
class Teacher extends Person {
getName () {
return super.getName()+' go'
}
}
const teacher = new Teacher()
teacher.getName() === 'caffrey go'
类中的访问类型和构造器
访问类型
- public 允许在类的内外被调用(默认)
- protected 允许在类内及继承的子类中使用
- private 允许在类内被使用
重写的方法的访问等级不能变严格,例如父类是protected,子类不能是private
class Person {
public name: string;
public sayHi () {
// 类内调用
this.name
console.log('hi')
}
}
const person = new Person()
// 类外
person.name = 'caffrey'
person.sayHi()
constructor
constructor会在类实例化(new Class)的时候被执行
class Person {
// 传统写法
// public name: string;
// constructor(name: string) {
// this.name = name;
// }
// 带访问类型的简化写法
constructor(public name: string) {}
}
const person = new Person('dell');
console.log(person.name);
- 父类和子类都有构造器
子类构造器需要调用父类的构造函数,否则会报错super(...)
即使父类没有参数,也要调用super()
class Person {
constructor(public name: string) {}
}
class Teacher extends Person {
constructor(public age: number) {
super('caffrey');
}
}
const teacher = new Teacher(28);
console.log(teacher.age); // 28
console.log(teacher.name); // caffrey
静态属性,getter和setter
类里面的getter和setter
class Person {
constructor(private name: string) {}
get getName () {
return this.name + ' go';
}
}
const person = new Person('caffrey')
// get直接getName调用,不需要person.getName()
console.log(person.getName)
// 'caffrey go'
private的属性(私有属性)一般使用_name命名
class Person {
constructor(private _name: string) {}
get name() {
return this._name + ' go';
}
set name(name: string) {
const realName = name.split(' ')[0];
this._name = realName;
}
}
const person = new Person('caffrey');
// get
console.log(person.name);
// set
person.name = 'caffrey go';
console.log(person.name);
设计模式:单例模式
只能生成一个类的实例(不允许外部以new Demo()的方式创建实例)
private私有限制符,只允许内部调用,默认public
static静态属性,将方法直接挂载在类上面,而不是类的实例上面
class Demo {
private static instance: Demo;
// 不允许外部以new Demo()的方式创建实例
private constructor (public name: string) {}
// static将方法直接挂载在类上面,而不是类的实例上面
// new Demo可以在类内调用
// static getInstance == public static getInstance
static getInstance () {
if(!this.instance) {
this.instance = new Demo('caffrey go');
}
return this.instance;
}
}
// demo1 demo2完全相同,而不是两个不同实例
const demo1 = Demo.getInstance();
const demo2 = Demo.getInstance();
// demo1.name === demo2.name === 'caffrey go'
class Axios {
private static instance: Axios | null = null
private constructor() {
// private构造函数,禁止外部调用创建新对象
}
static init() {
if (Axios.instance == null) {
console.log('创建Axios实例')
Axios.instance = new Axios()
}
return Axios.instance
}
}
const axios = Axios.init() // 创建Axios实例
const axios1 = Axios.init()
console.log(axios === axios1) // true
readonly只读
- 通过getter和setter实现
class Person {
private _name: string;
constructor (name: string) {
this._name = name;
}
get name () {
return this._name;
}
}
const person = new Person ();
console.log(person.name);
// 报错,没有设置getter的私有属性无法读取
person.name = 'hello';
console.log(person.name);
- readonly
class Person {
public readonly name: string;
constructor (name: string) {
this.name = name;
}
}
const person = new Person ();
console.log(person.name);
// 报错,readonly这样的public属性只能读不能改
person.name = 'hello';
console.log(person.name);
抽象类
抽象类/方法
- 类的通性 => 抽象类
- abstract方法,具体实现不确定(只能定义,不能实现),继承的抽象方法必须实现
- 抽象类只能被继承,不能被实例化
// abstract类,通用的类
abstract class Geom {
width: number;
getType () {
return 'Geom'
}
// abstract方法,具体实现不确定(只能定义,不能实现)
abstract getArea (): number;
}
class Circle extends Geom {
// 继承的抽象方法必须实现
getArea() {
return 123;
}
}
class Square {}
class Triangle {}
抽象类和接口
- 抽象类是把类里面相关的通用的东西抽象出来
- 接口是把各种对象等的通用性东西的提炼
interface Person {
name: string;
}
interface Teacher extends Person {
teachingAge: number
}
interface Student extends Person {
age: number
}
const teacher = {
name: 'caffrey',
teachingAge: 3
}
const student = {
name: 'go',
age: 18
}
const getUserInfo = (user: Person)=> {
console.log(user.name)
}
getUserInfo(teacher);
getUserInfo(student);