1 定义变量并声明类型
1.1 原始数据类型
let username: string = '小明'; // 字符串
let count: number = 100; // 数字,支持 十/十六/二/八 进制
let flag: boolean = true; // 布尔,只能是 true/false
let u: undefined = undefined; // undefined,用处不是很大
let timer: null = null; // null,用处不是很大
function gerName(str: string): void{} // 空 void,没有任何类型,函数的没用返回值的使用 void ,返回值为空( undefined )
let obj: any // 任意类型
// 这里当类型不确定的时候,就可以使用 any 任意类型,不到万不得已不使用
// Unknow 类型和 any 一样可以容纳任意类型比 any 安全
// 字面量
let animal: 'dog' // 字面量
animal = 'cat' // 报错
animal = 'dog' // 通过
1.2 复杂类型
let arr: number[] = [1,2,3,4,5,true] // 数组 array, 报错,true 不属于 number
let let tuple1: [string, boolean] = ['测试', true]; // 元祖 tuple
// 接口 interface
interface Device {
readonly id: number // 不可改变,定义完后不能更改
type: string
width: number
height: number
color?: string // 添加了 ? 代表可以没有
}
// 定义 phone 的类型为 Device ,Device 上定义的 id 只能赋值一次,属性 type、width、height 必须有,属性 color 可以没有
let phone: Device = {
id: 1,
type: '手机',
width: 0.07',
height: 0.18',
};
// 输入类型number number 返回类型number
function sum(num1: number, num2: number, num3?: number): number{
return num1 + num2
}
const sum1 = (num1: number, num2: number): number => {
return num1 + num2;
}
// () 里面是输入的形参的类型
// => 代表是 返回值 的类型
// : 后面的都是声明类型,和代码逻辑没有什么关系
let mysum:(num1: number, num2: number)=>number = sum1;
interface Isum {
(num1: number, num2: number): number
}
let mysum1: Isum = sum1;
let haha: number | string // 联合类型,在没赋值之前只能访问共同的方法、属性
haha.length // number 没有length 属性
haha.toString()
haha.valueOf()
haha = 'string'
haha = 123
// 直接 let a: object; 没有什么意义
let character: { name: string, age: number } // 对象 object
character = {
name: '张三',
age: 18
} // 属性必须在类型 { name: string; age: number; } 中
// 直接 let a: object; 没有什么意义
let character: { name: string, age: number } // 对象 object
character = {
name: '张三',
age: 18
} // 属性必须在类型 { name: string; age: number; } 中
2 断言 type inference
function getLen(params: number | string): number{
// 使用 as 断言,params 可以是 number 或 string 类型,断言为 string 才能有 length 属性
const str = params as string
/**
* 或者
* const str = <string>params; // 使用 <类型> 断言,功能同上面的 as
*/
if(str.length){
return str.length
}
return str.toString().length
}
3 类型守卫 type guard
// 遇到联合类型的时候,使用 类型守卫可以 缩小范围
function getLen2(params: number | string): number{
if(typeof params === 'string'){
return params.length
}
return params.toString().length
}
// 类型守卫 除了 typeof 之外 ,还有 instanceof、 in
4 类 class
Public
: 修饰的属性或方法是共有的 在 任何地方 都能访问Private
: 修饰的属性或方法是私有的 只有 本类 中访问Protected
: 修饰的属性或方法是受保护的 在 本类 和 子类中 能够访问
class Parent {
static species: string = 'human' // 使用 static 修饰的属性是通过 类 去访问
static readonly username: string = '小明' // 给属性添加上 readonly 就能保证该属性只读,不能修改,如果存在 static 修饰符,写在其后
public name: string
private money: number
protected age: number
constructor(name: string){
this.name = name
}
eat(){
console.log(`${this.name}在吃饭`);
}
}
let zs = new Parent('张三');
zs.eat()
class Son extends Parent {
private son_money: number
private son_age: number
constructor(name: string){
super(name)
this.son_money = super.money // 错误,money 为私有属性,只能在类 Parent 中访问
this.son_age = super.age // 类 Parent 的 age 属性可被子类访问
}
}
console.log(Parent.species);
Parent.username = '小红' // 错误的,username 为只读属性,不可修改
上面的 name
money
age
属性都是通过 实例 去访问的
使用 static
修饰的属性是通过 类 去访问,是每个实例共有的
同样 static
可以修饰 方法,用 static
修饰的方法称为 类方法,可以使用类直接调用
TS
新增的抽象类,不希望直接使用该类创建实例 (不能被new) 把它设置为抽象类,让它不能被实例化,只能被继承,
// 抽象类 abstract : 在 class 前面 添加 abstract 修饰符,
// 举个例子:一个动物的抽象类,有个叫的方法,不可能 每个动物的叫声一样吧,我们可以把它设置为抽象方法,具体功能子类进行实现(该怎么叫就由子类来写)
abstract class Animal {
public name: string
constructor(name: string){
this.name = name
}
abstract barking(): void // 抽象方法,没有方法体
}
class Cat extends Animal {
constructor(name: string){
super(name)
}
barking(){
console.log('喵喵喵~');
}
}
5 接口 interface
接口: 为了解决 继承 的困境(一个类只能继承另一个类不能实现多继承)
还有一种情况,人能够洗衣服,洗衣机也能洗衣服,洗衣机和人找不到一个共同的父类,我们可以把洗衣服这个功能抽离出来写成接口,人 和 洗衣机 去实现这个接口就行
可以用 implements
来实现接口
// 衣服接口
interface Clothes {
washClothes(): void
}
// 人类
class Person implements Clothes {
washClothes(){
console.log('手洗');
}
}
// 洗衣机类
class wMachine implements Clothes {
washClothes(){
console.log('机洗');
}
}
接口多实现
// 衣服接口
interface Clothes {
washClothes(): void
}
// 吃接口
interface Eat {
eatMeal(): void
}
// 人类
class Person implements Clothes,Eat {
washClothes(){
console.log('手洗');
}
eatMeal(){
console.log('人在吃');
}
}
接口之前可以继承
// 衣服接口
interface Clothes {
washClothes(): void
}
// 吃接口
interface Eat extends Clothes {
eatMeal(): void
}
// 人类
class Person implements Eat {
washClothes(){
console.log('手洗');
}
eatMeal(){
console.log('人在吃');
}
}
6 枚举 enum
常量是在项目中经常使用,虽然 const
可以声明常量,但是有的常量取值是在一个范围里的,这里我们就需要使用 enum
来进行处理
数字枚举
// 枚举星期
enum Week {
Monday, Tuesday, Wednesday, Thurday, Friday, Saturday, Sunday
}
// 默认从 0 开始
console.log(Week.Monday); // 0
console.log(Week.Tuesday); // 1
console.log(Week.Wednesday); // 2
console.log(Week.Thurday); // 3
// 通通过下标获取
console.log(Week[0]); // Monday
console.log(Week[1]); // Tuesday
console.log(Week[2]); // Wednesday
console.log(Week[3]); // Thurday
// 修改枚举中初始值
enum Week {
Monday = 4, Tuesday, Wednesday, Thurday, Friday, Saturday, Sunday
}
// 修改之后依次增加
console.log(Week.Monday); // 4
console.log(Week.Tuesday); // 5
console.log(Week.Wednesday); // 6
console.log(Week.Thurday); // 7
字符串枚举
enum Week {
Monday = 'Monday',
Tuesday = 'Tuesday',
Wednesday = 'Wednesday',
Thurday = 'Thurday',
Friday = 'Friday',
Saturday = 'Saturday',
Sunday = 'Sunday',
}
// 获取一个值后 对 week 枚举的值进行匹配
const vale = 'Tuesday'
if(vale === Week.Tuesday){
console.log('匹配成功');
}else{
throw new Error('匹配失败');
}
常量枚举
在 enum 前面添加一个 const 即可,它提高了性能 为什么呢?把上面字符串枚举编译成 js 例子,和 常量枚举编译 贴出来对比一下
/******************** 字符串枚举 ***********************/
// 枚举星期
var Week;
(function (Week) {
Week["Monday"] = "Monday";
Week["Tuesday"] = "Tuesday";
Week["Wednesday"] = "Wednesday";
Week["Thurday"] = "Thurday";
Week["Friday"] = "Friday";
Week["Saturday"] = "Saturday";
Week["Sunday"] = "Sunday";
})(Week || (Week = {}))
// 获得一个值后 对 week 枚举的值进行匹配
var vale = 'Tuesday';
if (vale === Week.Tuesday) {
console.log('匹配成功');
}
else {
throw new Error('匹配失败');
}
/******************** 常量枚举 ***********************/
// 获得一个值后 对 week 枚举的值进行匹配
var vale = 'Tuesday';
if (vale === 'Tuesday' /* Tuesday */) {
console.log('匹配成功');
}
else {
throw new Error('匹配失败');
}
常量枚举直接找出 Week.Tuesday
上面一截都没了
7 泛型
泛型就像一个占位符一个变量,在使用的时候我们可以将定义好的类型像参数一样传入,原封不动的输出
// 这里 T 是相当于一个占位符,在方法(变量,接口....等等)后面添加 <T>
function getValue<T>(params: T): T {
return params
}
// 在使用 getValue这个方法的时候 只需要在 实参 规定好类型,编译器能够知道我们的参数类型,并将它们赋值给 T
function getValue<123>(params: 123): 123
getValue(123)
// 多个参数
function getValue<T, U>(params: [T, U]): [T, U] {
return params
}
// 在使用的时候,聪明的就判断出 传入的类型,并修改了 T,U,真的很方便
function getValue<number, string>(params: [number, string]): [number, string]
getValue([123, '123'])
可以使用 interface 来约束 泛型
在 T
后面 extends Ilen
,定义 Ilen
里面代码表示,T
必须要有 length
属性,这样在 方法里面调用 params.length
就不会报错
interface ILen {
length: number,
}
function getLength<T extends ILen>(patams: T):number {
return params.length
}
getLength('str') // √
getLength([]) // √
getLength(123) // ×
在 类 使用泛型
class Kitchen<T>{
makeCake(name: T){
console.log('厨房制作了'+name+'蛋糕');
}
}
let kit = new Kitchen<string>()
kit.makeCake('草莓') // √
kit.makeCake(12345) // ×
在 接口 使用泛型
interface keyValue<T, U>{
key: T
value: U
}
let test: keyValue<string, number> = { key: 'test', value: 12345 }
let test2: keyValue<number, string> = { key: 12345, value: 'str' }
在 数组 使用泛型
// 一开始我们都这样定义类型
let myarr: number[] = [1, 2, 3, 4, 5]
// 使用泛型
let myarr1: Array<number> = [1, 2, 3, 4, 5]
let myarr2: Array<string> = ['1', '2', '3', '4', '5']
8 类型别名
使用 type
给类型取别名
type test = number
let count_number: test = 123
type test2 = number | string
let str: test2 = '1234'
let str2: test2 = 12345
9 交叉类型
用 &
进行连接,把类型都组合起来,变量赋值必须满足 交叉类型
interface Itest {
key: string
}
type test4 = Itest & { value: string }
let mytest: test4 = { key: '哈哈', value: '哈哈' }