本文是ts入门学习的记录,如有问题欢迎大家指出。
一、数据类型
1、原始类型
- Number
- String
- Boolean
- BigInt
- Symbol
- Null
- Undefined
其中 null 和 undefined 较为特殊,是其他任意类型的子集,赋值给其他数据类型的变量不会报错。
let name:string = undefined;
let age:number = null;
- any
若变量定义 any 类型,变量允许访问任意类型的属性和方法。当数据类型确定时,应避免使用(可以任意调用方法和属性,使其丧失作用)。
2、引用类型
- Object
- Array
- Tuple
- Function
- 其他
二、Array 和 Tuple
// 定义数组,定义数组后可以使用数组的方法和属性
// 不允许往数组中添加其他类型的数据,arr.push['123'] 报错
let arr:number[] = [1, 2, 3];
// 定义元组,元组是特殊的数组,允许使用数组的属性和方法
let tup: [number, string] = [10, 'hello'];
// 如上定义,允许往元组中添加 number 或者 string 类型的值,若其他类型报错
tup.push(10);
虽然类数组具备数组一部分的属性,但是数组和类数组的类型是不同的,如果在方法中将类数组赋值给数组,会报错。
元组一定程度上限定数据类型的数组,其本身还是数组,可以使用数组方法。
三、interface接口
interface 用来对对象的形状进行描述,对函数进行描述。
命名一般会首字母大写。
interface Animal {
name: string;
age: number
}
// 其形状必须完全和 Animal 一致
let dog:Animal = {
name: '小白',
age: 1
}
如果希望对象中一些字段可以不被匹配,可以使用可选属性(?)。
如果希望对象中一些字段不被修改,可以使用可读属性(readonly)。和 const 类似,只是用于属性。
interface Animal {
readonly id: number;
name: string;
age?: number
}
// age 可以不被定义
let dog:Animal = {
id: 1,
name: '小白'
}
// id 不可以被修改,dog.id = 2 报错
三、函数
函数需要约定输入和输出。
声明类型(=>是ts中声明类型的方法,凡是在:后面都是声明类型和实际的逻辑没有什么关系)。
function add (x:number, y:number):number {
return x + y;
}
// 以函数表达式的方式定义函数
// 注意:冒号之后的=>不是es6中的箭头函数,而是ts中定义函数类型的标志
const add1: (x: number, y:number) => number = add
// 使用 interface 描述函数的形状
interface Sum {
(x:number, y:number): number
}
const add2:Sum = add
如果一个参数可以不被匹配,可使用可选参数。注意:可选参数后不可有确定的参数
function add (x:number, y:number, z?:number):number {
return z ? x+y+z : x + y;
}
四、联合类型
在使用联合类型,不能确定变量到底是哪种类型时,该数据只能访问联合类型共有的属性和方法。
let item:number|string;
item = 3;
item = '3';
console.log(item.value);
五、类型推论
类型推论是指当我们没有定义变量的类型,给变量赋值时,ts 会推断该变量的类型,给该变量一个确切的类型。
let name = 'believe'
// ts 会自动将 name 的数据类型设置为 string,再给 name 赋值其他类型的值是会报错
六、类型断言
可以使用 as 关键字告诉 ts,这个变量确切的类型,之后可以访问这个数据类型下的属性和方法
注意:这里并没有改变变量的数据类型。
function getLength(item: number|string):number {
let str = item as string
if (str.length) {
return str.length;
} else {
let num = item as number;
return num.toString().length;
}
}
类型守护: 通过typeof等判断数据类型,并对其进行相应处理
七、calss类
访问修饰符:
类(定义了一切事物的抽象特点)
对象(类的实例)
面向对象特性:封装、继承、多态
readonly 只能读不能写
- public:共有的,都能访问
- private:私有的,不能在类的外部访问
- protected:受保护的,其和私有的区别在于 protected 修饰的属性或方法可以在子类中访问
class Animal {
readonly name:string
constructor(name) {
this.name = name
}
run() {
return `${this.name} is running`
}
}
class Dog extends Animal{
bark() {
return `${this.name} is barking`
}
}
class Cat extends Animal{
static categories=['animal']
constructor(name) {
super(name);
console.log(this.name)
}
run() {
return `Meow, ${super.run()}`
}
}
const snake=new Animal('lily')
// snake.name = '123' 报错
console.log(snake.run())
const dog = new Dog('xiaogou')
console.log(dog.bark())
console.log(dog.run())
const cat = new Cat('maomao')
console.log(cat.run())
console.log(Cat.categories)
类可以使用 implements 来实现接口,实现逻辑的提取和验证。接口之间可以有继承的关系,和类的继承相似。
interface Radio {
switchRadio (trigger: boolean): void;
}
interface Battery {
checkBattery(): void
}
interface RadioWithBattery extends Radio{
checkBattery(): void
}
class Car implements Radio{
switchRadio (trigger: boolean) {
}
}
// 以下两种效果相同相同
/*class Phone implements Radio,Battery {
switchRadio (trigger: boolean) {
}
checkBattery() {}
}*/
class Phone implements RadioWithBattery{
switchRadio (trigger: boolean) {
}
checkBattery() {}
}
八、枚举
枚举,在一定范围内的一系列常量
枚举默认会被从0开始赋值,手动赋值会接着上一个递增
// 数字枚举
enum Direction {
Up=10,
Down,
Left,
Right
}
// 可以看成数组,反向的取值
console.log(Direction.Up)
console.log(Direction[0])
// 字符串枚举
enum Direction {
Up='Up',
Down='Down',
Left='Left',
Right='Right'
}
枚举值分为常量值和计算值,只有常量值可以计算常量枚举
九、泛型
定义函数和类时,不预先指定类型,而在使用时才指定类型
名称叫什么都可以,相当于占位符
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 result1 = swap(['str', 123])
约束泛型
在使用泛型时,由于不能提前知道是哪种类型,不能随意的操作变量的属性和方法
// 这种解决方案不完美,规定其为数组,不能传入其他类型
function echoArr<T>(arg:T[]):T[] {
console.log(arg.length)
return arg
}
const result = echoArr([1,2,3])
使用 extends 使泛型满足特定的约束条件,而不时想传入什么就传入什么
interface Length {
length:number
}
function echoLength<T extends Length>(arg:T):T {
console.log(arg.length)
return arg
}
const str = echoLength('123')
const obj = echoLength({length: 10})
const arr = echoLength([1,2,3])
泛型在其方面的应用
类
// 创建特定数据类型的队列
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)
queue.push(2)
console.log(queue.pop().toFixed())
console.log(queue.pop().toFixed())
interface 接口
interface KeyPair<T, U> {
key: T,
value: U
}
let kp1: KeyPair<number, string> = {key:1, value: 'str'}
let arr: Array<number> = [1, 2]
泛型的作用
- 创建特定类型的容器
- 灵活的约束参数的类型
- 在函数使用时,函数的类型推断不会流入函数体内,使用表达式不能明确的绑定,所以使用泛型来打破这一鸿沟
十、类型别名、交叉类型
类型别名
使用 type 来定义类型别名
type 定义了类型的别名,用于交叉组合类型的情况;interface 是一种独特的类型
let sum: (x:number,y:number) => number
const result = sum(1,2)
type PlusType = (x:number,y:number) => number
let sum2: PlusType
const result1 = sum2(1,2)
字面量
特殊的类型,确定了变量只能等与特定的值
const str: 'name' = 'name'
type Directions = 'Up'|'Down'|'Left'|'Right'
let toWhere: Directions = 'Up'
交叉类型
interface Name {
name: string
}
// person具有age和name属性
type Person = Name & {age: Number}
let person: Person = {name: '123', age:1}
十一、声明文件
声明文件,使用 declare 关键字,来告诉ts这个类已经被定义,通常放入一个单独的文件通常以 .d.ts 结尾。
declare 并没有定义类的实现,仅仅定义了类型,来应对编译的检查。
declare var JQuery:(selector:string)=> any
JQuery('#foo')
十二、内置类型
const a: Array<number> = [1,2,3]
const date = new Date()
date.getTime()
const reg = /abc/
reg.test('abc')
Math.pow(1,2)
// dom 和 bom
let body = document.body
let allLis = document.querySelectorAll('Li')
allLis.keys()
// 根据类型推断,回调函数中的参数自动获取数据类型
document.addEventListener('click', (e)=> {})
Utility Types
Partial 把所有的数据变为可选
Omit 可以忽略某个传入类的属性
interface Person {
name: string,
age: number
}
let viking: Person = {name: 'viking', age: 1}
type Person1 = Partial<Person>
let viking2 = {}
type Person2 = Omit<Person, 'name'>
let viking3 = {age: 1}