1、下载并安装node.js
2、使用npm全局安装typeScript
3、创建一个ts文件
4、使用tsc对ts文件进行编译
通过类型声明变量,指定类型后,为变量赋值时,TS编译器会自动检查值是否符合类型生命,符合则赋值,否则报错
类型声明给变量设置了类型,使用变量只能存储某种类型的值
语法:
let 变量:类型
let 变量:类型=值
function fn(参数:类型,参数:类型):类型{
......
}
- let a: number = 2
- let str: string = '你好'
- a = 3
-
- function fn(a: string) {
- console.log(a);
- }
- fn('123')
-
- // 布尔类型:boolean
- let flag = false;
- // flag=123 报错
- flag = true;
- // 数字类型:number
- let num = 10; //十进制
- let num1 = 0b1010; // 二进制
- let num2 = 0o12; // 八进制
- // 字符串类型:string
- let str = '123';
- str = '';
- // undefined和null
- let u = undefined;
- let n = null;
- // undefined和null可以作为其他类型的子类型
- // 可以把undefined和null赋值给其他类型的变量
- let c = undefined;
- let str1 = null;
- // 数组
- // 定义数组一:
- let arr1: number[] = [1, 2, 3]
- arr1 = [3, 4, 5]
-
- // 定义数组二:泛型
- let arr2: Array
= [12, 13, 14] -
- // 对象
- // object表示非原始类型,除了number,string,boolean之外的类型
- let obj: object = {}
- // 字面量
- // obj=123 报错
- obj = { name: '张三' }
- obj = undefined
- obj = null
- obj = []
- obj = new String()
- obj = String
any:任何类型
- let h: any = 123
- h = false
- h = '泥嚎'
- h = {}
- h = []
- let newArr: any[] = [100, 2, '你好', true]
- // console.log(newArr[0].split('')); ts编译不报错,但是split是字符串的操作方法,100并不是字符串
void:空值,表示没有任何返回值的函数
- function fn(): void {
- console.log(123);
- }
- console.log(fn());
ts在没有明确指定类型的时候推测一个类型
有两种情况:
- let t = 123 // ts将t定义成一个number类型,通过类型推断
- // t='' 报错
-
- let g; // 定义变量的时候没有赋值,则定义为any类型
- g = 123
- g = true
- g = ""
- g = []
- g = {}
表示取值可以为多种类型中的一种
- // flag true 1 false 0
- let f: boolean | number | string = true // 此时只能访问联合类型的所有类型共有的属性或方法
- f = 123 // 再次赋值,走类型推断,给变量定义一个类型,此时就可以使用该类型的属性或方法
- f = '123'
- f = false
- // console.log(f.split(''));
接口是对行为的抽象,用于对对象形状进行描述,可以理解为一种约束
接口的首字母一般大写
定义的变量比接口多或少一些属性都是不被允许的
可选属性:有时不需要完全匹配一个形状可以使用可选属性:?表示可选属性,定义对象?的属性可有可无
?表示可选属性,定义对象?的属性可有可无
任意属性:有时我们希望一个接口允许有任意的属性,一旦定义了任意属性,那么任意属性和可选属性的类型都必须是它的类型的子集
[propName:string]:any
一个接口中只能定义一个任意属性,如果接口中有多个类型的属性,则可以在任意属性中使用联合类型
[propName:string]:number | string | boolean
只读属性:可以用readonly定义只读属性
- interface IPerson {
- readonly id: number,
- name: string,
- age: number,
- sex?: string,
- [propName: string]: number | string | boolean
- // [propName: string]: any
- }
- let p: IPerson = {
- id: 1,
- name: '张三',
- age: 12,
- height: 168,
- width: true
- }
- // p.id=2 报错 因为id是只读属性
- interface INewArray {
- [index: number]: number // 任意属性,index表示数组中的下标
- }
- let arr: INewArray = [1, 2, 3, 4]
(参数:类型,...):返回值的类型
- interface ISearchFunc {
- // (参数:类型,...):返回值的类型
- (a: string, b: string): boolean
- }
- // 参数,返回值
- const fun1: ISearchFunc = function (a: string, b: string): boolean {
- return a.search(b) !== -1
- }
- console.log(fun1('123', '1'));
接口可以继承其他多个接口,再让类实现接口
- interface IRun {
- run()
- }
- interface ISwim {
- swim()
- }
- // 接口可以继承其他多个接口,再让类实现接口
- interface IActive extends IRun, ISwim {}
- class I implements IActive {
- run() {
- console.log('run');
- }
- swim() {
- console.log('swim');
- }
- }
接口继承类中的实例属性和实例方法
参数a和b都是Number类型
:number表示该函数的返回值为number类型
- function add(a: number, b: number): number {
- return a + b
- }
- let cc: number = add(1, 2)
- console.log(cc);
-
- // 函数表达式:匿名函数
- let add2 = function (a: number, b: number): number {
- return a + b
- }
- console.log(add2(1, 2));
- // 函数完整的写法
- let add3: (a: number, b: number) => number = function (a: number, b: number): number {
- return a + b
- }
可选参数 ?
- let getName1 = function (x: string = "李", y?: string): string {
- return x + y
- }
必选参数不能位于可选参数后面
默认参数可以放在必选参数或可选参数后面
- let getName2 = function (x: string, y?: string, z: string = "李"): string {
- return x + y + z
- }
ES6 中,可以使用 ...rest
的方式获取函数中的剩余参数(rest 参数)
- function fn(x: string, y: string, ...args) {
- console.log(x, y, args);
- }
- console.log(fn('1', '1', 1, 2, 3, 4, 5));
函数重载:函数名相同,形参不同的多个函数
没有使用函数重载时:有一个缺点,就是不能够精确的表达,输入为数字的时候,输出也应该为数字,输入为字符串的时候,输出也应该为字符串。
使用函数重载可以解决这个问题:
可以使用重载定义定义多个newAdd的函数类型
类型断言:可以手动指定一个类型
两种语法:
当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型中共有的属性或方法
而有时候,我们确实需要在还不确定类型的时候就访问其中一个类型特有的属性或方法
比如:定义一个函数,获取到一个数字或字符串的长度
解决方法:使用类型断言
- function getLength(x: string | number): number {
- if ((x as string).length) {
- return (
x).length - } else {
- return x.toString().length
- }
- }
- console.log(getLength(90));
将任何一个类型断言为any类型,any类型可以访问所有的属性和方法,但是它极有可能掩盖了真正的类型错误,所以如果不是非常确定,就不要使用as any
(window as any).a = 10
将any断言为一个具体的类型
a1被断言为number类型。a2此时被断言为string类型
- function abc(x: any, y: any): any {
- return x + y
- }
- let a1 = abc(1, 2) as number
- let a2 = abc('1', '2') as string
- console.log(a1);
- console.log(a2);
通过类型type给类型起别名
- type s = string // 通过type给类型起别名
- let str2: s = '123'
- str = '456'
- let a3:string|number|boolean=123
- let b1:string|number|boolean=true
常用于给联合类型起别名,可以写为:
- type all = string | number | boolean
- let a3: all = 123
- let b1: all = true
用来约束取值只能是某个字符串中的一个
比如:张三,张三丰,张大炮,names只能为其中的一个
- type stringType = '张三丰' | '张三' | '张大炮'
- // let names: stringType = '张三1' 报错
- let names: stringType = '张三'
元祖(Tuple)合并了不同类型的对象
- let arr4: number[] = [1, 2, 3, 4]
- // 数值和字符串
- // 元祖(Tuple)合并了不同类型的对象
- let Tarr: [number, string] = [123, '123']
- // 添加内容的时候需要是number或string类型
- Tarr.push('456')
- Tarr.push(123)
- // Tarr.push(true) 报错
使用枚举类型给一组数据赋值名称,可以通过名称拿取值,也可以通过值拿取名称
手动赋值注意:尽量不要写一些重复值,会覆盖
- enum NumberType {
- one = 1, // 手动赋值,如果没有赋值,第一个参数默认为0,后面的值会根据前一个值递增+1
- two,
- three,
- four
- }
- console.log(NumberType.one); //1
- console.log(NumberType.two); //2
常数枚举是使用const enum定义的枚举类型
常熟枚举与普通枚举的区别是,他会在编译阶段被删除,并且不能包含计算成员
- const enum obj1 {
- o, b, j
- }
- console.log(obj1.o); // 0
- console.log(obj1.j); // 2
外部枚举(Ambient Enums)是使用declare enum定义的枚举类型
declare定义的类型只会用于编译时的检查,编译结果中会被删除
- declare enum ABC {
- a, b, c
- } // 编译过程中会被删除
- console.log(ABC.a);
类:描述了所创建的对象共同的属性和方法
- class Person {
- name: string
- age: number
- constructor(name: string, age: number) {
- this.name = name
- this.age = age
- }
- sayHi(str: string) {
- console.log('hi' + str);
- }
- }
- let q = new Person('张三', 18) // new的时候,会执行类中构造方法constructor
- q.sayHi('张三')
通过继承扩展现有的类
继承:类与类之间的关系
类与类之间存在继承关系,通过extends进行继承
子类可以调用父类的方法,通过super
- class Animal { // 父类
- name: string
- age: string
- constructor(name: string, age: string) {
- this.name = name
- this.age = age
- }
- sayHi(str: string) {
- console.log('hi' + str);
- }
- }
- // 子类
- class Dog extends Animal {
- constructor(name: string, age: string) {
- // 调用父类构造函数,使用super
- super(name, age)
- }
- // 可以调用父类的方法,还可以重写父类的方法
- sayHi(str: string) {
- console.log('我是dog类的shyHi方法');
- super.sayHi('狗子') // 可以用super调用父类的方法
-
- }
- }
- const aaa = new Animal('小猫', '三岁')
- aaa.sayHi('小猫')
- const ddd = new Dog('小狗', '一岁')
- ddd.sayHi('可爱的狗子')
存取器:可以帮助我们控制对象成员的访问
- class Name {
- firstName: string
- lastName: string
- constructor(firstName: string, lastName: string) {
- this.firstName = firstName
- this.lastName = lastName
- }
- // 设置存取器
- // 读取器--->用来读取数据
- get fullName() {
- return this.firstName + '-' + this.lastName
- // return '张三'
- }
- // 设置器--->用来设置数据
- set fullName(value) {
- let names = value.split('-')
- this.firstName = names[1]
- this.lastName = names[0]
- }
- }
- const n3 = new Name('张', '大炮')
- // console.log(n3);
- n3.fullName = '张-三丰' // 没有设置器时fullName是只读的
- console.log(n3.fullName);
静态方法、静态属性
只属于类自己的属性和方法
- class A {
- static name1: string
- // constructor(name: string) {
- // this.name = name
- // }
- static sayHi() {
- console.log('hi');
-
- }
- }
- const a5 = new A()
- console.log(A.name1);
- A.sayHi()
-
- // console.log(a5.name1); 报错
- // a5.sayHi() 报错
public修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
- class B {
- public name1: string // 公有的属性
- public constructor(name: string) { // 公有的方法
- this.name1 = name
- }
- public p() {
- console.log(this.name1);
- }
- }
- const aa = new B('张三')
- console.log(aa.name1);
- aa.p()
private 修饰的属性或方法是私有的,不能在声明它的类的外部访问。包括其子类。但是这个属性和方法是可以被继承的
私有属性的属性和方法可以被继承,但是在子类中无法访问私有属性
protected修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
外部无法访问,但子类中可以访问到
readonly是只读属性,但是在构造函数是可以修改的
readonly以及三个修饰符(public、private、protected)定义在参数上,那就是创建并且初始化age参数
- class X {
- // readonly age: number // 只读属性,但是在构造函数是可以修改的
- // readonly以及三个修饰符定义在参数上,那就是创建并且初始化age参数
- // constructor(readonly age: number) {
- // constructor(public age: number) {
- // constructor(private age: number) {
- constructor(protected age: number) {
- // this.age = age
- }
- update() {
- // this.age = 15 报错,不能被修改,只读属性
- }
- }
- const xx = new X(13)
- console.log(xx);
- // xx.age = 12 报错,不能被修改,只读属性
abstract定义一个抽象类,为子类服务
抽象类不允许被实例化,可以在子类中具体实现抽象类中的抽象方法
- abstract class Y { // abstract定义一个抽象类
- abstract name: string // 抽象属性
- // constructor(name){
- // this.name=name
- // }
- abstract sayHi() // 不能有具体实现
- }
- // 不能被实例化
- class Z extends Y {
- name: string
- constructor(name) {
- super()
- this.name = name
- }
- // 子类中具体实现抽象类中的抽象方法
- sayHi() {
- console.log('hi');
- }
-
- }
- const z = new Z('张三')
- console.log(z.name);
- z.sayHi()
类可以作为类型给变量定义类型
- class Car {
- name: string
- constructor(name: string) {
- this.name = name
- }
- }
- class Ben extends Car {
- constructor(name) {
- super(name)
- }
- }
- const car: Car = new Car('bm')
- const ben: Ben = new Ben('')
实现(implements)是面向对象中的一个重要概念
举例来说,人会唱歌跳舞,动物也会唱歌跳舞,我们就可以把唱歌跳舞提取出来作为一个接口,让人和动物去实现它:
- interface ISing {
- // 这个方法是没有任何的实现
- sing()
- }
- interface IDance {
- dance()
- }
- class P implements ISing, IDance { // 人:唱歌、跳舞
- sing() {
- console.log('sing');
- }
- dance() {
- console.log('dance');
- }
- }
-
- class Ani implements ISing, IDance { // 动物:唱歌、跳舞
- sing() {
- console.log('sing');
- }
- dance() {
- console.log('dance');
- }
- }
- const p1 = new P()
- const an = new Ani()
- p1.sing()
- p1.dance()
-
- an.sing()
- an.dance()
接口中的属性在合并时会简单的合并到一个接口中,相当于取并集
函数合并--->函数重载
合并的属性的类型必须是唯一的
类的合并与接口合并是一样的
- interface Cat {
- name: '大橘',
- gender: '女'
- }
- interface Cat {
- name: '大橘',
- age: 1
- }
- const cat: Cat = { name: '大橘', age: 1, gender: '女' }
使用泛型,在定义时不需要先确定类型,而是使用的时候再去确定
如果没有确定的话,就会走类型推断
原则上不推荐使用any,用T表示任意输入的类型
例如:
- // 需求:定义一个函数,传入两个参数,第一个参数是数据,第二个参数是数量
- // 函数的作用:根据熟练产生对应个数的数据,存放在一个数组中
- // (123,3)--->[123,123,123]
- function getArr
(value: T, count: number): T[] { - const arr: T[] = []
- for (let i = 0; i < count; i++) {
- arr.push(value)
- }
- return arr
- }
- console.log(getArr
(123, 3)); - console.log(getArr
('你好', 3));
定义泛型的时候,可以一次定义多个类型参数
- // [123,'123']--->['123',123]
- function updateArr
(t: [T, U]): [U, T] { - return [t[1], t[0]]
- }
- console.log(updateArr
(['123', 123])); // [ 123, '123' ] - console.log(updateArr
([true, 123])); // [ 123, true ]
泛型约束,约束这个任意输入的类型,必须要有length属性
例如:获取一个参数的长度
- interface ILength {
- length: number
- }
- function getLength1
extends ILength>(x: T): number { - return x.length
- }
- // console.log(getLength1(123)); // 报错number类型没有length属性
- console.log(getLength('123'));