Why TypeScript
任何可以使用Javascript来编写的应用,最终会由JavaScript编写。
—— Jeff Atwood, 2007
任何可以使用Javascript来编写的优秀的大型应用,最终会由TypeScript编写。
—— 韩骏,2019
使用TypeScript的优点
- 程序更容易理解
- 开发效率更高
- 在现代IDE的帮助下进行代码块之间的跳转
- 自动补全
- 丰富的接口提示
- 更少的错误
- 变量名
- 类型比较错误
- 非常好的包容性
- 完全兼容Javascript
- 第三方库可以单独编写类型文件
- 流行的项目都支持:React、Vue、Ant Design
缺点
- 短期开发成本(添加类型)
- 学习成本
安装
npm install typescript -g
tsc -v
tsc xxx.ts
ECMAScript定义的js数据类型
- 7种原始数据类型(值本身是无法被改变的,操作之后一定返回新的)
- Boolean
- Null
- Undefined
- BigInt
- String
- Symbol
- Object
原始类型变量声明
let isDone: boolean = false;
let age: number = 12;
let name: string = 'llr';
let message: string = `age is ${age}`;
// undefiled & null 是其它原始类型的子类型
let u: undefined = undefined;
let n: null = null;
let num: number = undefined
export {}
任意类型any,尽量避免使用
let notSure: any = 3;
notSure = 'maybe a string';
notSure = true;
// 属性与方法的结果都是any
notSure.myName
notSure.myName()
联合类型(union types)
let numberOrString: number | string = 123;
numberOrString = 'abc';
数组array与元组tuple
//数组
let arrOfNumbers: number[] = [1, 2, 3];
arrOfNumbers.push(4)
// 元组:限定了一定类型的数组
let user: [string, number] = ['llr', 1]
Interface 接口
- 对对象的shpe进行描述
- 对类(class)进行抽象
- Duck Typing (鸭子类型)
- 维基百科:“如果一个东西长得像鸭子,像鸭子一样睡觉,像鸭子一样吃饭,那它就是鸭子”
- 动态编程语言中的对象的推断策略
- 更关注对象如何被使用,而不是对象本身
interface Person {
// readonly比较像const,区别是一个用在属性上面,一个用在变量上面
readonly id: number,
name: string;
age: number;
cool?: boolean
}
let llr: Person = {
id: 1,
name: 'llle',
age: 20,
}
函数与类型推断
function add(x:number, y: number, z?: number): number {
if(typeof z === 'number'){
return x + y + z
} else {
return x + y
}
}
let result = add(2, 3);
let result2 = add(2, 3, 5)
// 函数的类型声明
const add2: (x: number, y: number, z?: number) => number = add
let str = 'str';
// ts的compiler会推断str的类型为str
str = 123;
类 Class
- 类(Class)定义了一切事物的抽象特点
- 对象(Object):类的实例
- 面向对象(OOP)三大特性:
- 封装
- 继承
- 多态
class Animal {
name: string;
constructor(name: string){
this.name = name
}
run() {
return `${this.name} is running.`
}
}
class Dog extends Animal {
bark(){
return `${this.name} is barking.`
}
}
class Cat extends Animal {
run(){
return `cat ${this.name} is running.`
}
}
let snack = new Animal('python')
console.log(snack.run())
类的修饰符
默认public:可以访问,更新
private:属性与子类都无法访问
protective:子类可以访问,外部无法访问
静态属性与静态方法:与类的实例没有关系
static
类和接口
interface Radio {
switchRadio(): void
}
interface Battery {
checkBatteryStatus(): number
}
class Car implements Radio, Battery {
switchRadio(){
}
checkBatteryStatus(): number {
return 100
}
}
class CellPhone implements Battery{
checkBatteryStatus(): number {
return 10
}
}
枚举
默认数字枚举
enum Direction {
Up,
Down,
Left,
Right,
}
// 0
console.log(Direction.Up)
// "Up"
console.log(Direction[0])
字符串枚举
enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',
}
// UP
console.log(Direction.Up)
常量枚举(可以提升性能)
会直接将使用枚举的值编译成结果
const enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',
}
if("UP"===Direction.Up){
console.log(Direction.Up)
}
---------------编译之后的代码------------
if("UP"===Direction.Up){
console.log(Direction.Up)
}
泛型Generics
定义函数、接口和类的时候,不预先指定类型;在使用的时候再确定类型的特征
function echo<T>(arg: T): T{
return arg
}
const result: string = echo('str')
const result2 = echo(123)
const result3 = echo(true)
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]]
}
const resultx = swap(['Str', 123])
resultx[1] = "str"
约束泛型
interface IWithLength {
length: number,
}
function echoWithLength<T extends IWithLength>(arg: T): T {
console.log(arg.length)
return arg
}
// 约束泛型:使传入值满足特定的约束条件(参数必须有length属性),duck typing的例子
const str = echoWithLength('str')
const arr = echoWithLength([1,2,3])
const obj = echoWithLength({length: 10})
泛型在类上的应用,描述类的函数类型
class Queue<T> {
private data = [];
push(item: T) {
return this.data.push(item)
}
pop(): T {
return this.data.shift()
}
}
const queue = new Queue<number>()
queue.push(1)
console.log(queue.pop().toFixed())
const queue2 = new Queue<string>()
queue2.push('str')
console.log(queue2.pop().length)
泛型在接口上的应用,描述接口类型
interface KeyPair<T, U> {
key: T,
value: U;
}
let kp1: KeyPair<number, string> = {key: 1, value: 'str'}
let kp2: KeyPair<string, number> = {key: 'test', value: 123}
let arr: number[] = [1,2,3]
// Array是一个内置的interface
let arr2: Array<number> = [1,2,3]
泛型在函数上的应用,描述函数类型
interface IPlus<T> {
(a: T, b: T): T
}
function plus(a: number, b: number): number {
return a + b;
}
function connect(a: string, b: string): string {
return a + b
}
const a: IPlus<number> = plus
const b: IPlus<string> = connect
自定义类型type
类型别名type aliases
type PlusType = (x: number, y: number) => number
function sum(a: number, b: number): number {
return a + b;
}
const sum2: PlusType = sum
type NameResolver = () => string
type NameOrResolver = string | NameResolver
function getName(name: NameOrResolver): string {
if(typeof name === 'string'){
return name
}else {
return name()
}
}
类型断言type assertion
//类型断言不是类型转换,不能断言成联合类型不存的类型
function getLength(input: string | number): number {
// const str = input as String
// if(str.length) {
// return str.length
// }else {
// const number = input as Number
// return number.toString().length
// }
if ((<string>input).length) {
return (<string>input).length
} else {
return input.toString().length
}
}
声明文件
// 文件名格式为xxx.d.ts:jQuery.d.ts
declare var jQuery: (selector: string) => any
一般采用第三方声明文件: npm install --save @types/jquery
由第三方组织DefinitelyType个组织统一管理,需要提交pull request,旨在针对不同库都提供高质量声明文件的社区。
网友评论