初体验:安装和运行ts
$ npm install -g typescript
$ tsc -v
$ tsc helloworld.ts
一、ts类型声明
Boolean \ Number \ String \ Array \ Function \ Object \ Symbol \ undefined \ null
void \ any \ never \ 元组 \ 枚举 \ 高级类型
类型注解, 就是类型声明
1.基础类型
// 原始类型
let isDone: boolean = false
let count: number = 10
let name: string = 'smile'
// symbol - 具有唯一的值
let s1: symbol = Symbol()
let s2 = Symbol()
console.log(s1 === s2) //error
// Array 类型
let arr1: number[] = [1, 2, 3]
let arr2: Array<number> = [1, 2] // 泛型语法
let arr2: Array<number | string> = [1, 2, '4'] // 联合类型
// Tuple 元组
一种特殊的数组,它限定了元素的类型和个数
let tuple: [number, string] = [0, '1']
let tuple: [number, string] = ['good', '1'] //error
// void
没有任何返回值的类型
let noReturn = () => {}
function warnUser(): void {
console.log("message")
}
// undefined, null
是任何类型的子类型
let un: undefined = undefined
let nu: null = null
// any 类型
全局超级类型
// Unknown 类型
对any类型的补充,
unknown 类型只能被赋值给 any 类型和 unknown 类型本身,当中间类型赋值变化时,会error
// never
永远不会有返回值的类型
2.对象和函数类型
// 对象类型
let stu: object = { name: '张三', age: 18 }
console.log(stu)
注: 一般对象类型不会这样申明
而是直接写让 TS 做自动类型判断或者,如接口等
// 函数类型
1) 返回值类型可省略,利用了ts的类型推断功能
2) 有多种声明方式,一般靠类型推断,或者是接口来描述
let add = (x: number, y: number):number => return x + y
3.枚举类型
枚举 - 一组有名字的常量集合
解决的问题: 1)可读性差,很难记住数字的含义; 2)可维护差,牵一发动全身
// 01 - 数字枚举
enum Role {
Reporter = 1,
Owner,
}
console.log(Role.Reporter)
// 02 - 字符串枚举
enum Message {
Success = '成功了',
Fail = '失败了'
}
// 03 - 常量枚举
const enum Month {
Jan,
Feb,
Mar,
Apr = Month.Mar + 1,
// May = () => 5
}
let month = [Month.Jan, Month.Feb, Month.Mar]
// 04 - 异构枚举(数字和字符串的混合)
enum Enum {
A,
B,
C = "C",
E = 8,
}
----------
// 枚举成员
1) 枚举成员的值是不可修改的
2) 常量成员和计算成员
二、ts高级类型
1.交叉类型
2.联合类型
3.类型保护与区分类型
类型别名 字面量类型 可辨识联合 this类型 索引类型 映射类型
4.ts断言
1.类型断言:
// “尖括号” 或者 as语法
let strLength: number = (<string>someValue).length;
let strLength: number = (someValue as string).length;
2.非空断言
x! --- 将从x值域中排除 null 和 undefined
1) 忽略 undefined 和 null 类型
function myFunc(maybeString: string | undefined | null) {
const onlyString: string = maybeString; // Error (严格语法时报错)
const ignoreUndefinedAndNull: string = maybeString!; // Ok
}
2) 调用函数时忽略 undefined 类型
type NumGenerator = () => number;
function myFunc(numGenerator: NumGenerator | undefined) {
const num1 = numGenerator(); // Error
const num2 = numGenerator!(); //OK
}
3.确定赋值断言
通过 let x!: number; 确定赋值断言,Ts编译器就会知道该属性会被明确地赋值
三、TS接口
1. 对传入参数进行约束
2. 对对象类型声明的描述
3. 对类里面的属性、方法进行声明约束,实现这个接口的类必须实现接口里面的属性和方法
// 声明接口
interface TypeA {
...
}
// 声明a为TypeA类型并赋值
let a: TypeA = { … }
1.可选属性 ?
2.只读属性 readonly
3.任意属性 可以使用 [propName: string]: any 定义任意属性名取string类型值,属性值取any类型值。
interface Person {
name: string;
age?: number;
readonly x: number;
[propName: string]: any;
}
1.属性类型接口
// 接口描述对象User
interface User {
name: string
age?: number
readonly isMale: boolean
say: Say
}
const getUserName = (user: User) => user.name
2.函数类型接口
// 接口描述函数类型Say
interface Say {
(words: string) : string
}
3.通用类型接口
// 接口描述通用类型
interface Config {
width?: number;
[propName: string]: any;
}
不确定接口个数时,这样Config可以有任意数量的属性
4. 类类型接口
实现(implements)
一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些公有的特性,这时候可以吧特性提取成接口,用implements关键字实现
interface Watch{
watch():string
}
class Tv implements Watch {
watch() { …… }
}
class Phone implements Watch {
watch() { …… }
}
interface Other{
call();
play();
}
class Phone implements Watch, Other {
private watch() { …… }
call() { …… }
play() { …… }
}
一个类可以实现多个接口,但只能extends自一个类(接口用于对类的一部分行为的抽象,不包括具体的实现)接口只能描述类的公共(public)部分
- 实例类类型接口(只会对实例的属性进行限制,方法也是类的属性. 接口描述了类的公共部分)
//因为eat也可以说是一个属性
interface Animal {
name: string
eat(str: string): void
}
class Dog implements Animal {
private age: number = 2
//接口来限制类(类中必须有name属性和eat方法)
//类中也可以有其他的属性
constructor(public name: string) {}
eat(str: string) {
console.log(this.name + '吃' + str)
}
}
let dog: Dog = new Dog('狗')
dog.eat('狗粮')
- 构造器与静态类接口
// 定义了两个接口, ClockConstructor为构造函数所用, ClockInterface为实例方法所用
// 定义一个构造函数 createClock,它用传入的类型创建实例
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface
}
interface ClockInterface {
tick()
}
function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
return new ctor(hour, minute);
}
class DigitalClock implements ClockInterface {
constructor(h: number, m: number) { }
tick() {
console.log("beep beep")
}
}
class AnalogClock implements ClockInterface {
constructor(h: number, m: number) { }
tick() {
console.log("tick tock")
}
}
let digital = createClock(DigitalClock, 12, 17)
let analog = createClock(AnalogClock, 7, 32)
5. 混合类型接口
//这个混合类型限制的变量本身是个函数,但是有reset方法和interval属性
interface Counter {
(start: number): number
interval: number
reset(): void
}
function getCounter(): Counter {
let counter: Counter = function (start: number): number {
return start++
} as Counter
counter.interval = 123
counter.reset = function () {
this.interval = 0
}
return counter
}
let c = getCounter()
c(10)
c.reset()
console.log(c.interval)
// 混合类型接口 -- 单例模式
interface Lib {
(): void;
version: string;
doSomething(): void;
}
let lib = (() => {}) as Lib
lib.version = '1.0.0'
lib.doSomething = () => {}
// 混合类型接口 -- 多例模式
interface Lib {
(): void;
version: string;
doSomething(): void;
}
function getLib() {
let lib = (() => {}) as Lib
lib.version = '1.0.0'
lib.doSomething = () => {}
return lib;
}
let lib1 = getLib()
lib1()
let lib2 = getLib()
lib2.doSomething()
6. 接口扩展 - extends
// 可以继承多个接口
interface VIPUser extends User, SupperUser {
broadcast: () => void
}
7. 继承类类型接口
类可以当作接口来使用,也可以被接口所继承
class Control {
private state: any
}
interface SelectableControl extends Control {
select(): void
}
class Button extends Control implements SelectableControl {
select(): void {}
}
class Radio extends Control {
select(): void {}
}
三、TS类
1.属性与方法
class Person {
// 静态属性
static max: number = 100
// 成员属性
name: string
// 构造函数 - 类被初始化时,自动执行方法
constructor(n: string) {
this.name = n
}
// 静态方法
static getClassName() {
return "Class name is Greeter";
}
// 成员方法
run(): void {
console.log(this.name)
}
}
// 构造函数就是在类被初始化的时候,自动执行的一个方法
// 我们通过这个构造方法经常作很多需要提前完成的工作,比如显示页面前我们要从后台得到数据
// 01 实例类类型
// 类本身就是一种类型,类的名字可以直接作为类型名。
// 声明p为Person类型并赋值(默认为any)
let p: Person = new Person('张三')
// 02 静态类类型(类本身)
// typeof Person是表明该对象是一个Person类的类型,而不是Person的实例类型
let Person2: typeof Person = Person
Person2.max = 150
console.log(Person === Person2)
2.类的继承 extends、super
在ts中,我们可以通过 extends 关键字来实现继承,是类与类的层次模型(一个类只能继承一个父类)
// 基类 / 超(父)类
class Person {
public name: string
constructor(name: string) {
this.name = name
}
...
}
// 派生类 / 子类
class Student extends Person {
age: number
constructor(name: string, age: number) {
super(name) // super 继承基类的构造器,并向基类的构造器传参,super必须写在第一行
this.age = age
}
work() {
console.log(this.age)
}
}
let s = new Student('李四', 18)
s.run()
s.work()
3.类的修饰符(控制类成员的可访问性)
public: 公有, 在类、子类、类外部都可以访问
protected: 保护, 在类、子类里可以, 在类的外部无法访问
private: 私有, 在类里面可以访问, 在子类和类的外部无法访问
readonly: 只读, 在声明时或构造函数里被初始化
在子类中通过super调用父类原型的属性和方法时,也只能够访问到父类的public和protected方法,否则会报错
class Animal {
private name: string
readonly age: string
constructor(theName: string) {
this.name = theName
}
}
4.寄存器
TS 中也可以对一个属性时用 get 和 set 方法对一个属性内部的获取和赋值进行拦截
let passcode = 'secret passcode'
class Employee {
private _fullName: string
get fullName(): string {
//对fullName属性进行拦截
return this._fullName
}
set fullName(newName: string) {
if (passcode && passcode == 'secret passcode') {
this._fullName = newName
} else {
console.log('Error: Unauthorized update of employee!')
}
}
}
let employee = new Employee()
employee.fullName = 'Bob Smith'
if (employee.fullName) {
alert(employee.fullName)
}
5.静态属性和静态方法
静态属性和静态方法必须使用 -类名- 调用。
静态方法调用不了实例方法和实例属性。(静态域的加载是在解析阶段,实例化是在初始化阶段)
class Xiaogege {
age: number = 28
static name:string = ‘静态属性’;
static say() {
console.log(‘静态方法’)
console.log(this.name)
console.log(this.age) // 错误
}
}
console.log(Xiaogege.name)
Xiaogege.say()
let xiaoge = new Xiaogege()
xiaoge.say() // 错误
console.log(xiaoge.name) // 错误
6.抽象类
使用 abstract 声明的类,为抽象类(abstract定义抽象类和抽象方法)
不能直接被实例化,只能被其他类所继承
在工作中,我们也会把这样的需求用接口来实现
abstract class Animal {
name: string;
constructor (name:string) { this.name = name }
abstract eat () : void
abstract eat () : { // error
console.log(`${this.name}吃骨头`
}
}
class Gou extends Animal {
constructor (name:string) { super(name)}
eat () : void{ console.log(`${this.name}吃骨头`) }
abstract say () : void // error
}
const gou : Gou = new Gou(‘汪汪’)
gou.eat()
7.多态
类类型(class) -- 多态 => 重写方法
父类定义一个方法不实现,让子类去实现,每个子类的该方法有不同的表现
class Animal {
name: string;
constructor (name:string) { this.name = name }
eat ():void
}
class Gou extends Animal {
constructor (name:string) { super(name)}
eat (){ console.log(`${this.name}吃骨头`) }
}
class Mao extends Animal {
constructor (name:string) { super(name)}
eat () { console.log(`${this.name}吃鱼干`) }
}
const gou : Gou = new Gou(‘汪汪’)
gou.eat()
const mao : Mao = new Mao(‘喵喵’)
mao.eat()