- TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准(ES6 教程)
- TypeScript 由微软开发的自由和开源的编程语言。
- TypeScript 设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript 可以运行在任何浏览器上。
JavaScript 与 TypeScript 的区别:
- TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。
- TypeScript 可处理已有的 JavaScript 代码,并只对其中的 TypeScript 代码进行编译。
1、TypeScript作用域问题
// 如果我们在一个ts文件中添加了一个全局变量,那么在其他ts文件中就不能再去声明这个变量了
// 例:
1.ts
const a = 123
2.ts
const a = '123'
// 2.ts文件中就会报出,a已经声明过了,不能再声明
// 解决办法:
// 我们可以把2.ts作为一个模块导出,export {},因为模块是有单独作用域的,所以和1.ts文件不会产生冲突
2、Object类型
- object类型并不是单只对象类型,而是泛指所有的非原始类型。也就是对象、数组、函数
// 例:
const foo: object = // 可是是函数 function() {}、数组[]、对象{}
// 如果要单独定义对象的话,可以使用
const foo: {} = {}
// 如果要单独针对对象里面的字段进行定义的话,可以使用
const foo: {name: string, age: number} = { name: 'jack', age: 23 }
// 注意:定义的对象必须要跟我们定义的变量的解构完全一致,否则会报错
3、数组类型
const foo: Array<number> = [1,2,3] // 表示定义一个数组中只能是数字的变量,其他会报错
// 或
const foo: number[] = [1,2,3]
// 例子:计算一个数组的和,但是传的值必须是数字
function sum(...args: number[]) { // 代表必须全部是由数字组成的数组类型
return args.reduce((prev, current) => {
return prev + current
}, 0)
}
console.log(sum(1,2,3,4,5)) // 15
4、元组类型
- 明确元素数量以及每个元素类型的一个数组
// 例子:
const arr: [name: string, age: number] = [name: 'jack', age: 23]
// 这种就是元组类型
5、枚举类型
enum upOrDown {
down = 0,
up = 1
}
// 定义枚举
// 或
enum upOrDown {
down,
up
}
// 默认从0开始网上递增
// 如果定义的值不是数字,那就必须的写上对应的值
const goods = {
name: '天猫精灵',
price: 99,
index: upOrDown.down // 0 未上架、1 已上架
}
// 通过upOrDown.dowm / upOrDown.up拿到对应的类型
// 注意:枚举类型会影响到我们编译后的结果
// 上面代码编译后对应的js文件会变成如下
var upOrDown;
(function (upOrDown) {
upOrDown[upOrDown["down"] = 0] = "down";
upOrDown[upOrDown["up"] = 1] = "up";
})(upOrDown || (upOrDown = {}));
const goods = {
name: '天猫精灵',
price: 99,
index: upOrDown.down // 0 未上架、1 已上架
};
// 如果不想这样做的话我们可以定义 const
const enum upOrDown {
down,
up
}
// 编译后:
const goods = {
name: '天猫精灵',
price: 99,
index: 0 /* down */ // 0 未上架、1 已上架
};
6、函数类型
- 函数定义的方式有两种:函数声明、函数表达式
// 1、函数声明
function foo(name: string, age: number): string {
return `my name is ${name}, age ${age}`
}
foo('jack', 23)
/**
* 1、foo函数我们定义了两个参数,那么我调用foo方法的时候也必须传两个参数,不能多也不能少
* 2、并且这两个参数我们分别定义了name必须为字符串类型,age必须为数字类型。如果我们传入的
* 是其他类型也会报错
* 3、我们还定义了返回值必须为string类型,如果返回的是其他类型也会报错
* 4、如果我们定义可选参数可以在参数名后面加上'?',例子:age?: number。注意:可选参数必须定义在参数 * 的最后
*/
// 2、函数表达式
const foo = function(name: string, age: number): string {
return `my name is ${name}, age ${age}`
}
foo('jack', 23)
/*
* 1、接受函数的这个变量也是有类型的,比如我们现这个函数返回的是一个字符串,那么这个foo变量应该就是
* string类型
* 2、如果我们在编辑器中写上函数的话,会提示const foo: (name: string, age: number) => string
*/
7、任意类型(any)
- any是动态类型可以接受任意的值,不会报任何语法上的错误,any是不安全的,所以不要轻易的去使用
function foo (value: any) {
console.log(value)
}
foo(12)
foo('string')
foo(true)
// 以上定义的any类型所有值都可以接受
8、隐式类型推断
- 隐式类型推断就是你在定义一个变量或者其他的时候,如果你没有给它定义类型,它会根据你的代码或者值推断出其类型
let age = 18
/**
* 比如你定义一个age = 18的变量,在编辑器中你会看到这样一个注解:let age: number
* 意思就是定义了一个变量age,类型是number类型
*/
// 如果你将这个变量重新赋值,例:
age = '123'
// 这样的话编辑器中就会报:let age: number,不能将类型“string”分配给类型“number”。
建议:给每个变量添加明确的类型,这样便于后期理解我们的代码
9、类型断言(as)
- 类型断言的意思就是说:使用者非常确定我们定义的值是什么类型,但是代码并不确定。这个时候我们就可以使用断言的方式告诉代码,我们定义的是什么类型
const list = [1, 2, 3, 4, 5] // 定义一个变量全是数字的数组
const res = list.find(i => i > 0) // 获取数组中第一个大于0的数字,返回的肯定是一个数字
const result = res * res // 这个时候代码中会提示:const res: number | undefined,意思就是说res是个数字也有可能是 undefined,所以我们就不能是 * 来进行计算
解决方法:使用断言的方式
const num = res as number // 断言res一定是一个number类型
const result = res * res // 这样计算就不会出现代码报错的问题
10、接口(interface)
- 接口就是用来约束一个对象的结构,一个对象去实现一个接口,那它就必须去拥有这个接口当中的所有成员,以及对应成员的类型
function foo (person) {
console.log(person.name)
console.log(person.age)
}
// 这个时候person就会报:(parameter) person: any
// 这个时候我们可以给这个参数定义一个接口
interface Person {
name: string
age: number
}
function foo (person: Person) {
console.log(person.name)
console.log(person.age)
}
foo({
name: 'jack',
age: 23
})
/*
* 我们在调用这个方法的时候,就必须得传一个对象,这个对象就必须得包含name和age
* 并且name是string类型,age是number类型,否则会报语法错误
*/
// 接口中还可以定义:可选成员、只读成员、动态成员
// 可选成员:就是说我们定义的接口中字段可以有也可以是undefined,例:
interface Person {
name: string
age: number
work?: string // 我们可以在work后面加一个 ? 来体现出我们这个字段是可选值
}
// 只读成员:就是说我们定义的字段是不能修改的
interface Person {
name: string
age: number
work?: string
readonly sex: string // 这个就是我们定义的成员只能读取,不能修改
}
// 动态成员:在我们不确定的情况我们可以定义动态成员
interface Person {
[key: string]: string // key就是我们定义的键,类型为string,后面的string是值的类型
}
const person: Person = {
}
这样我们就可以随意的想person对象中添加值
person.name = 'jack'
person.sex = '男'
11、类
- 类就是一个具体事物的抽象特征,TypeScript中的类其实和js中的类差不多
// 1、基本使用
class Person {
name: string
age: number
// 以上是和js的区别,我们如果要在构造函数中是this的话,必须在上面定义一个对应的值
constructor(name: string, age: number) {
this.name = name
this.age = age
}
sayHi(msg: string): void {
console.log(`I am ${this.name}`)
}
}
// 类的访问修饰符
1、private(私有属性)
class Person {
name: string
private age: number // 如果我们在age上面定义了一个private私有属性的话,那这个age只能在类的内部去访问
constructor(name: string, age: number) {
this.name = name
this.age = age
}
sayHi(msg: string): void {
console.log(`this is ${this.name}`)
console.log(`this is ${this.age}`) // 可以访问到age属性
}
}
const jack = new Person('name', 18)
console.log(jack.name) // 可以访问到name属性
console.log(jack.age) // 访问不到age属性
2、public(公有属性)
class Person {
public name: string // 不加public默认就是public,建议添加,这样便于后期代码的可读性
private age: number // 如果我们在age上面定义了一个private私有属性的话,那这个age只能在类的内部去访问
constructor(name: string, age: number) {
this.name = name
this.age = age
}
sayHi(msg: string): void {
console.log(`this is ${this.name}`)
console.log(`this is ${this.age}`) // 可以访问到age属性
}
}
const jack = new Person('name', 18)
console.log(jack.name) // 可以访问到name属性
console.log(jack.age) // 访问不到age属性
2、protected(受保护的)
// 只能在子类中访问到,外部也是访问不到的,这是和private的区别
class Person {
public name: string // 不加public默认就是public,建议添加,这样便于后期代码的可读性
private age: number // 如果我们在age上面定义了一个private私有属性的话,那这个age只能在类的内部去访问
protected gender: true
constructor(name: string, age: number) {
this.name = name
this.age = age
this.gender = true
}
sayHi(msg: string): void {
console.log(`this is ${this.name}`)
console.log(`this is ${this.age}`) // 可以访问到age属性
console.log(`this is ${this.gender}`) // 可以访问到gender属性
}
}
class Student extends Person {
constructor(name: string, age: number) {
super(name, age)
console.log(this.gender) // 能访问到gender属性
}
}
const jack = new Person('name', 18)
console.log(jack.name) // 可以访问到name属性
console.log(jack.age) // 访问不到age属性
console.log(jack.gender) // 访问不到gender属性
注意:如果在构造函数上使用private方法,那这个类型就不能在外部被实例化
class Student extends Person {
private constructor(name: string, age: number) {
super(name, age)
console.log(this.gender)
}
}
const tom = new Student() // 无法实例化
解决方法:
class Student extends Person {
private constructor(name: string, age: number) {
super(name, age)
console.log(this.gender)
}
// 添加静态方式去返回这个实例对象
static create (name: string, age: number) {
return new Student(name, age)
}
}
const tom = Student.create('tom', 18) // 这样就可以create静态方法去创建实例对象了
未完待续......