- 动态类型语言(Dynamically Typed Language)运行期间才会作类型检查;
- 静态类型语言(Statically Typed Language)编译期间进行类型检查;
Ts简介:
- typescript 可以理解为 可扩展的 js 或者是 js 的超集;
- 静态类型风格的类型系统;
- 从es6到es10 甚至是 esnext 的语法支持;
- 兼容各种浏览器,各种系统,各种服务器,完全开源;
为什么要使用 ts,解决了什么问题,对我有什么提高?
- 因为类型,使得程序更加容易理解;
- 效率更高,支持代码块之间的跳转和代码补全;
- 更少的错误(编译期间能发现更多的错误);
- 非常好的包容性,完全兼容js,第三方库可以单独编写类型文件;
一、原始类型和 Any类型:
primitive value(原始类型:值不可变)
JS: Boolean 、Null、Undefined、Number、String、Bigint、Symbol
TS: boolean 、null、undefined、number、string
非原始类型
JS: Object
TS: interface、any(任意类型)
代码示例:
let isDone: boolean = false
let age: number = 10
let firstName: string = 'viking'
let message: string = `Hello, ${firstName}`
let u: undefined = undefined
let n: null = null
let num: number = undefined
let notSure: any = 4
notSure = 'maybe a string'
notSure = true
notSure.myName
notSure.getName()
二、数组和元组:
Array && Tuple
代码示例:
let arrOfNumbers: number[] = [1,2,3]
arrOfNumbers.push(3)
function test() {
console.log(arguments);
// arguments类数组, 有一些数组的属性,但是不能调用数组的方法
}
// 元组在一定程度上代表限制了类型的数组
let user: [string, number] = ['viking', 20]
三、interface: 定义 object 类型, 对对象的进行描述
readonly 只读
? 代表可选属性
interface Person {
readonly id: number;
name: string;
age?: number;
}
let viking: Person = {
id: 1,
name: 'viking',
age: 20,
}
四、函数:
在ts中凡是在冒号后面都是在声明类型;
在参数后面用冒号约定输入表示参数类型;
在输入后面用冒号约定输出表示返回值类型;
? 代表参数可选;可选参数必须放在最后面,避免程序对参数的判断发生错乱;
// 函数声明写法
function add = (x: number, y: number, z?: number): number {
if (typeof z === 'number') {
return x + y + z
} else {
return x + y
}
}
// 函数表达式 => add 获得了一个类型
const add = (x: number, y: number, z?: number): number => {
if (typeof z === 'number') {
return x + y + z
} else {
return x + y
}
}
// 赋值
let add2: (x: number, y: number, z?: number): number =>number = add;
// interface 描述函数类型
interface ISum {
(x: number, y: number, z?: number): number
}
// 赋值
let add2: ISum = add
五、类型推论,联合类型和类型断言
4762ed4db6acc1d6ad17cfa014ac1cb.png// type inference: ts 会在没有明确声明一个类型的时候自动推断一个类型,再次赋值的时候如何和之前推论的值不一致,就会出现提示;
let str = 'str'
str=123 (警告如上图)
// union types (多种类型中的一种),当我们不确哪种类型的时候,只能访问联合类型的共有类型
let numberOrString: number | string
// 但是我们的确想要访问这个类型的方法的时候 使用 as 强制把这个变量看成某种类型,并不是类型转化
function getLength(input: string | number): number {
const str = input as string
if (str.length) {
return str.length
} else {
// 类型断言 input as number
const number = input as number
return number.toString().length
}
}
//或者是使用 type guard 解决,当遇到联合类型的时候,使用if语句可以智能的缩小类型的范围,
//(typeof 关键字)
function getLength2(input: string | number): number {
if (typeof input === 'string') {
return input.length
} else {
return input.toString().length
}
}
六、Class
- 在JS中使用构造函数和原型链来实现继承;
- ES6 中语法糖=>原理还是原型链
类: 定义个一切失误的抽象特点;
对象:类的实例;
面向对象(OOP)三大特性:封装、继承、多态
封装: 隐藏内部实现逻辑;
继承: 子类、父类
多态:相同的方法,不同的响应
class Animal {
// 限制属性只读
readonly name: string;
constructor(name) {
this.name = name
}
run() {
return `${this.name} is running`
}
}
const snake = new Animal('lily')
console.log(snake.run())
// extends 继承
class Dog extends Animal {
bark() {
return `${this.name} is barking`
}
}
const xiaobao = new Dog('xiaobao')
console.log(xiaobao.run())
console.log(xiaobao.bark())
class Cat extends Animal {
// 静态属性
static categories = ['mammal']
constructor(name) {
super(name)
console.log(this.name)
}
run() {
return 'Meow, ' + super.run()
}
}
const maomao = new Cat('maomao')
console.log(maomao.run())
console.log(Cat.categories)
TS 如何增强类:
public 修饰的属性或者方法是共有的
private 修饰的属性或者方法是私有的
protected 修饰的属性或者方法是受保护的(子类可以调用,实例对象不行)
七、类和接口
// interface 对类的部分行为进行抽象,替代部分相同功能但是又不是子类和父类关系的情景;
interface Radio {
switchRadio(trigger: boolean): void;
}
interface Battery {
checkBatteryStatus(): void;
}
// 接口之间的继承
interface RadioWithBattery extends Radio {
checkBatteryStatus(): void
}
// Car implements (实现了) Radio 的方法
class Car implements Radio{
switchRadio(trigger: boolean) {
}
}
class Cellphone implements RadioWithBattery {
switchRadio(trigger: boolean) {
}
checkBatteryStatus() {
}
}
八、枚举
在一定范围内的一系列的常量:使用枚举
8eb52038d9d22786f2091ed2fafa607.png
// 数字枚举,默认从 0 开始自动递增的数据
const enum Direction {
Up = 10,
Down,
Left,
Right,
}
// 原理如上图
console.log(Direction.up); // 10
console.log(Direction[0]); // Up
// 字符串枚举,const 常量枚举,会提升性能,会直接把值翻译为结果,不会把枚举翻译为js代码, 如下图,并不是所有的枚举都可以使用常量枚举
const enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',
}
const value = 'UP'
if (value === Direction.Up) {
console.log('go up!')
}
549d7268c58d7e00aaa59545126ec4d.png
九、泛型
定义函数/类/接口时,不预先指定类型,而在使用的时候去推断类型,相当于一个占位符;
// 为了解决函数在传参和返回值确定情况下,使用场景局限性的问题,使用 any 会导致代码可读性较差;
// 根据传入的类型,类型推断
function echo<T>(arg: T): T {
return arg
}
const result = echo(true)
// 传入多个值的泛型
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]]
}
const result2 = swap(['string', 123])
function echoWithArr<T>(arg: T[]): T[] {
console.log(arg.length)
return arg
}
const arrs = echoWithArr([1, 2, 3])
// 约束泛型
interface IWithLength {
length: number
}
// 必须是拥有length属性的对象
function echoWithLength<T extends IWithLength>(arg: T): T {
console.log(arg.length)
return arg
}
const str = echoWithLength('str')
const obj = echoWithLength({ length: 10, width: 10})
const arr2 = echoWithLength([1, 2, 3])
// 泛型在Class中的使用
class Queue<T> {
private data = [];
push(item: T) {
return this.data.push(item)
}
pop(): T {
return this.data.shift()
}
}
const queue = new Queue<number>()
queue.push(1)
console.log(queue.pop().toFixed()) // toFixed 只能是number类型
// 泛型在 interface 中的使用
interface KeyPair<T, U> {
key: T
value: U
}
let kp1: KeyPair<number, string> = { key: 1, value: "string"}
let kp2: KeyPair<string, number> = { key: 'str', value: 2 }
let arr: number[] = [1,2,3]
let arrTwo: Array<number> = [1,2,3]
十、类型别名、字面量、交叉类型
// type aliase => 解决部分类型较长的问题 关键字 type
let sum: (x: number, y: number) => number
const result = sum(1,2)
type PlusType = (x: number, y: number) => number
let sum2: PlusType
const result2 = sum2(2, 3)
type StrOrNumber = string | number
let result3: StrOrNumber = '123'
result3 = 123
// 字面量 只能是primative value
const str: 'name' = 'name'
const number: 1 = 1
type Directions = 'Up' | 'Down' | 'Left' | 'Right'
let toWhere: Directions = 'Left'
// 交叉类型 和 联合类型相对应 (非)
为了实现对象组合的扩展
interface IName {
name: string
}
type IPerson = IName & { age: number }
let person: IPerson = { name: '123', age: 123 }
十一、TS内置类型
//global objects
const a: Array<number> = [1,2,3]
const date = new Date()
date.getTime()
const reg = /abc/
reg.test('abc')
//build-in object
Math.pow(2, 2)
//DOM and BOM
let body = document.body
let allLis = document.querySelectorAll('li')
allLis.keys()
document.addEventListener('click', (e) => {
e.preventDefault()
})
//Utility Types 功能类型
interface IPerson {
name: string
age: number
}
// Partial 返回的类型可以把类型属性变为可选
let viking: IPerson = { name: 'viking', age: 20 }
type IPartial = Partial<IPerson>
let viking2: IPartial = { name: 'viking' }
// IOmit 返回的类型可以忽略传入类型的某个属性
type IOmit = Omit<IPerson, 'name'>
let viking3: IOmit = { age: 20 }
网友评论