TypeScript是JavaScript的一种超集是一种强类型语言
原始类型 < Primitive Type >
原始数据类型
const a: string = 'foobar'
const b: number = 123 //NaN Infinity
const c: boolean = true //false
// 在非严格模式(strictNullChecks)下,
// string,number,boolean都可以为空
// const d: string = null
// const d: number = null
// const d: boolean = null
const e: void = undefined
const f: null = null
const g: undefined = undefined
// Symbol 是 ES2015 标准中定义的成员
// 使用它的前提是必须确保有对应的 ES2015 标准库的引用
// 也就是 tsconfig.json 中的 lib 选项必须包含 ES2015
const h: symbol = Symbol()
作用域问题
1.使用立即执行函数
(function(){
const a = 123
})()
2.export {}
const a = 123
export {}
Object Types<对象类型>
指的是除原始类型之外的类型,可以使用对象自变量的语法方式
const foo: object = function(){}//[] {}
const obj: { foo: number, bar: string } = { foo: 123, bar: 'strinf'}
Array Types
const arr1: Array<number> = [1, 2, 3]
const arr2: number[] = [1, 2, 3]
function sum(...args:number[]){
// 判断是不是每个成员都是数字
return args.reduce((prev,current)=>prev+current,0)
}
sum([1,2,3])//6
Tuple Types<元组类型>
指的是明确元素类型元素数量的一个数组
const tuple: [number, string] = [24,'shy']
const age = tuple[0]
const name = tuple[1]
const [age,num] = tuple
Object.entries({
foo:123,
bar:456
})
Enum Types <枚举类型>
特点:
1.给一组数值分别取上不同的名字
2.一个枚举中只会存在几个固定的值,并不会出现超出范围的可能性
可以使用object模仿枚举类型
const PostStatus = {
Draft: 0,
Unpublished: 1,
Published: 2
}
typeScript中使用enum去定义一个枚举值
enum PostStatus = {
Draft = 0,
Unpublished = 1,
Published = 2
}
如果不设置初始值的话默认从0开始依次赋值
enum PostStatus = {
Draft,
Unpublished,
Published
}
如果枚举值是字符串,需要设置初始值
enum PostStatus = {
Draft = 'aaa',
Unpublished = 'bbb',
Published = 'ccc'
}
枚举类型会入侵到运行时候的代码(会影响编译后的结果)
以枚举为数字类型为例 转译为js文件时
var PostStatus;
(function (PostStatus){
PostStatus[PostStatus['Draft'] = 0] = 'Draft'
PostStatus[PostStatus['Unpublished'] = 1] = 'Unpublished'
PostStatus[PostStatus['Published'] = 2] = 'Published'
})(PostStatus||(PostStatus={}))
使用常量枚举就会解决这个问题(在enum前加上const)
const enum PostStatus = {
Draft,
Unpublished,
Published
}
Function Types<函数类型>
声明型函数类型限制
function func1(a: number,b: number): string{
return 'funct1'
}
调用是必须传入两个number类型的值,少或多都会造成异常
当传入参数为可选参数时可以使用?的形式,但需要注意可选参数要放在最后
function func1(a: number,b?: number): string{
return 'funct1'
}
也可以使用给参数设置默认值
function func1(a: number,b: number = 10): string{
return 'funct1'
}
使用任意个数参数
function func1(...rest: number[]): string{
return 'funct1'
}
函数表达式类型限制
const func2:(a: number,b: number = 10) => string = function(a: number,b: number): string{
return 'funct2'
}
Any Types<任意类型>
不会进行类型检查,所以类型是不安全的
function stringify(value){
return JSON.stringify(value)
}
stringify('string')
stringify(123)
stringify(true)
let foo: any = 'string'
foo = 100
Type Inference<隐式类型推断>
根据变量的使用情况推断类型
let age = 18 //number
age = 'string' //age会报语法错误
当不设置初始值时,默认类型为any
建议为每个变量添加明确的类型,便于维护,理解
Type assertions<类型断言>
明确知道类型时
//假定这个nums来自一个明确的接口
const nums = [100,120,1320,130]
const res = nums.find(i=>i>0)
const square = res * res //res为number||undefined
在这种情况下我们需要明确res为number类型
使用类型断言的两种方式
1.as
const num1 = res as number
2.<number>
const num2 = <number>res //JSX 下不能使用,会和标签冲突
类型断言(代码在编辑阶段的概念)不是类型转换(代码在运行阶段的概念)
Interfaces<接口>
一种规范,一种约定
interface Post{
title: string; //结尾可以使用,;或不写
contet: string;
}
function printPost(post: Post) {
console.log(post.title)
console.log(post.contet)
}
printPost({
title: 'Hello TypeScript',
content: 'A JavaSctipt superset'
})
总结:接口就是用来约束对象结构,一个对象要实现接口,他就必须要拥有接口中约束的所有成员
可选成员
interface Post{
title: string; //结尾可以使用,;或不写
contet: string;
subTitle?: string //使用?表示为可选成员
}
只读成员
interface Post{
title: string; //结尾可以使用,;或不写
contet: string;
readonly summary: string//只读成员,不能修改
}
动态成员
interface Cache{
[key: string]: string //成员键与值都为字符串类型
}
const cache: Cache = {}
cache.foo = 'value1'
cache.bar = 'value2'
Classes<类>
描述一类具体事物的抽象特征
class Person {
name: string
age: number
constructor(name: string, age: number){
this.name = name
this.age = age
}
sayHi(msg:string):void{
console.log(`I am ${this.name},${msg}`)
}
}
private私有属性,只能内部访问
class Person {
name: string
private age: number
constructor(name: string, age: number){
this.name = name
this.age = age
}
sayHi(msg:string):void{
console.log(`I am ${this.name},${msg}`)
console.log(this.age)
}
}
const tom = new Person('tom',18)
只能访问到tom.name,不能访问到tom.age
public公有属性,默认就是public
protected 也是私有属性,只允许在子类中显示
class Person {
name: string
private age: number
protected gender:boolean
constructor(name: string, age: number){
this.name = name
this.age = age
this.gender = true
}
sayHi(msg:string):void{
console.log(`I am ${this.name},${msg}`)
console.log(this.age)
}
}
class Student extends Person{
constructor(name: string, age: number){
super(name,age)
console.log(this.gender)
}
}
接口:约束子类当中必须拥有某个成员(只是接口的抽象,不包含实现)
interface Eat{
eat(food: string): void //只做接口约定不做接口实现
}
interface Run{
run(distance: string): void //一个接口约束一个能力,一个类型实现多个接口
}
class Person implements Eat,Run {
eat(food: string): void {
console.log(`${food}`)
}
run(distance: string): void {
console.log(`${distance}`)
}
}
抽象类
抽象类:约束子类当中必须拥有某个成员(包含接口实现)
abstract class Animal {
eat(food: string): void {
console.log(`${food}`)
}
abstract run(distance: string): void {
console.log(`${distance}`)
}
}
只能继承不能new创建
class Dog extends Animal{
run(distance: string): void {
console.log(`${distance}`)
}
}
const d = new Dog()
d.eat('肉')
d.run('跑')
泛型
在定义函数接口或类时没有指定具体类型,在使用时再去指定类型的特征
function createArray<T> (length: number, value: T):T {
const arr = Array<T>(length).fill(value)
return arr
}
const res = createArray<string>(3,'str')//['str','str','str']
const res2 = createArray<number>(3,100)//[100,100,100]
TypeScript的优缺点
优点
- 增强了代码的可读性和可维护性
- 包容性,js可以直接改成ts,ts编译报错也可以生成js文件,兼容第三方库,即使不是ts编写的
- 社区活跃,完全支持es6
缺点
- 增加学习成本
- 增加开发成本,因为增加了类型定义
- 需要编译,类型检查会增加编译时长,语法和类型系统复杂的话时间特别特别长
- eval和new Function()这种操作类型系统管不到
- 和有些库结合时不是很完美