2019-09-21
TypeScript
0

目录

参数默认值+类型定义
super关键字
类型定义为class
getter setter(es6提供)
public、private、protected(TS提供)
公共修饰符(public)
私有修饰符(private)
受保护的修饰符(protected)
抽象类
泛型
泛型讲解
泛型变量
泛型类型
泛型约束
泛型类
类型推断
推断出通用类型
无法推断超级类型
上下文类型推断
keyof typeof
keyof
typeof
命名空间
declare
namespace
reference

TypeScript 是一种由微软开发的开源编程语言,它是 JavaScript 的超集,提供了静态类型检查、面向对象编程、泛型等高级特性,可以使 JavaScript 代码更加可读、可维护和可扩展。随着 TypeScript 在前端开发中的广泛应用,学习 TypeScript 已经成为了前端开发者必不可少的技能之一。

参数默认值+类型定义

单值定义

ts
class Animal { move(distance:number=0){ console.log(`Animal moved ${distance}m`) } }

对象定义

ts
class Animal { move(obj:{a:string,b:number}={a:'1',b:2}){ console.log(`Animal moved ${obj.a}${obj.b}m`) } }

super关键字

super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B的实例。

因此super()在这里相当于A.prototype.constructor.call(this)。

super.move()相当于A.prototype.move.call(this)。

类型定义为class

ts
class Animal { name:string constructor(name:string){ this.name=name } move(distance:number=0){ console.log(`${this.name} moved ${distance}m`) } } class Horse extends Animal { constructor(name:string){ super(name) } } let tom:Animal=new Horse('Tommy') tom.move(14)

getter setter(es6提供)

兼容性:存取器要求你将编译器设置为输出 ECMAScript 5 或更高。

不支持降级到 ECMAScript 3。

因为使用到了Object.defineProperty这个API

命令:

shell
tsc --target es5 index.ts
ts
class Person { private name:string constructor(name){ this.fullName=name } get fullName():string{ return this.name } set fullName(name:string){ this.name='Str '+name } } let p=new Person('Xiao Ming') console.log(p.fullName)

public、private、protected(TS提供)

公共修饰符(public)

默认为 public

ts
class Animal { public name: string // => name: string效果一致 public constructor(name: string) { this.name = name } } new Animal('wain').name // 可以被访问到

私有修饰符(private)

不可以被实例化访问,不可以被extends继承,完全私有

ts
class Animal { private name: string constructor(name: string) { this.name = name } } new Animal('Cat').name // ERROR: 'name' 是私有的.

受保护的修饰符(protected)

不可以被实例化访问,可以被extends继承

ts
class Animal { private name: string protected constructor(name: string) { this.name = name console.log('s1') } } let a=new Animal('1') // 无法被初始化,因为constructor是受保护的

抽象类

abstract 关键字是用于定义抽象类和在抽象类内部定义抽象方法。

抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。不同于接口,抽象类可以包含成员的实现细节。

ts
abstract class Department { name: string constructor(name: string) { this.name = name } printName(): void { console.log('Department name: ' + this.name) } abstract printMeeting(): void // 必须在派生类中实现 } class AccountingDepartment extends Department { constructor() { super('Accounting and Auditing') // 在派生类的构造函数中必须调用 super() } printMeeting(): void { console.log('The Accounting Department meets each Monday at 10am.') } generateReports(): void { console.log('Generating accounting reports...') } } let department: Department // 允许创建一个对抽象类型的引用 department = new Department() // 错误: 不能创建一个抽象类的实例 department = new AccountingDepartment() // 允许对一个抽象子类进行实例化和赋值 department.printName() department.printMeeting() department.generateReports() // 错误: 方法在声明的抽象类中不存在

泛型

泛型讲解

在像 C# 和 Java 这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

ts
// 定义泛型 function identity<T>(arg: T):T { return arg } // 使用泛型 let output1=identity<string>('myString') //方式一 let output2=identity(2) //方式二 类型推断

泛型变量

接收类型参数 T 和参数 arg,它是个元素类型是 T 的数组,并返回元素类型是T 的数组。 如果我们传入数字数组,将返回一个数字数组,因为此时 T 的的类型为 number。 这可以让我们把泛型变量 T 当做类型的一部分使用,而不是整个类型,增加了灵活性。

ts
function identity<T>(arg: T[]):T[] { console.log(arg.length) return arg } let output1=identity([1,2,3]) let output2=identity(['1','2','3']) let output3=identity([1,'2','3'])

泛型类型

方式一:

ts
function identity<T>(arg: T): T { return arg } let myIdentity: <T>(arg: T) => T = identity

方式二:对象字面量来定义泛型函数

ts
function identity<T>(arg:T):T { return arg } let myIdentity:{<T>(arg:T):T}=identity

方式三:泛型接口

ts
interface GenericIdentityFn<T>{ (arg:T):T } function identity<T>(arg:T):T { return arg } let myIdentity:GenericIdentityFn<number []>=identity

泛型约束

约束必须存在的字段类型

ts
interface Lengthwise { length: number } function loggingIdentity<T extends Lengthwise>(arg: T): T { console.log(arg.length) // OK return arg } console.log(loggingIdentity(1)) // ERROR console.log(loggingIdentity('1')) // OK

约束字段需要存在于对象中

ts
function getProperty<T,K extends keyof T>(obj:T,key:K){ return obj[key] } let x={a:1,b:2,c:3} getProperty(x,'a') // OK getProperty(x,'m') // ERROR

泛型类

ts
class GenericNumber<T> { zeroValue: T add: (x: T, y: T) => T } let myGenericNumber = new GenericNumber<number>() myGenericNumber.zeroValue = 0 myGenericNumber.add = function(x, y) { return x + y }

类型推断

推断出通用类型

为了推断 x 的类型,我们必须考虑所有元素的类型,这里有两种选择:number 和 null

let x = [0, 1, null]

无法推断超级类型

这里,我们想让 zoo 被推断为 Animal[] 类型,但是这个数组里没有对象是 Animal 类型的,因此不能推断出这个结果。最终会被推断为联合类型(Bee | Lion)[]

ts
class Animal { numLegs: number } class Bee extends Animal {} class Lion extends Animal {} let zoo = [new Bee(), new Lion()]

上下文类型推断

ts
window.onmousedown=function(mouseEvent){ console.log(mouseEvent.clickTime) // ERROR,TS会自己进行上下文推断 } // 解决问题: window.onmousedown=function(mouseEvent:any){ console.log(mouseEvent.clickTime) }

keyof typeof

keyof

返回键值的联合类型

ts
enum testEnum { a, b } const obj = {} const arr = [] type a = keyof {} // OK 返回never type b = keyof obj // ERROR type c = keyof [] // OK 返回Array.prototype的联合类型 type d = keyof arr //ERROR type e= keyof testEnum // OK 返回Number.prototype的联合类型

typeof

在ts中,额外的功能点是返回当前值的接口类型

ts
enum testEnum { a, b } const obj = {} const arr = [] type a = typeof {} // ERROR type b = typeof obj // OK 返回{} type c = typeof [] // ERROR type d = typeof arr // OK 返回 never[] type e= typeof testEnum // OK 返回testEnum的接口类型

命名空间

declare

定义的类型只会用于编译时的检查,编译结果中会被删除

ts
// 定义全局变量 declare var $:(param:()=>void)=>void // 定义全局函数 interface JqueryInstance { html:(html:string)=>JqueryInstance } // 函数重载 declare function $(readFunc:()=>void):void declare function $(selector:string):JqueryInstance // 定义对象 declare namespace $ { namespace fn { class init {} } } // 使用interface的语法, 实现函数重载(如果同时该值还是对象的话,就无法使用这种方式) interface Jquery { (readFunc:()=>void):void (selector:string):JqueryInstance } declare var $:Jquery

namespace

commonjs模式下,定义变量和函数会在全局定义。这个时候,我们不想变量在全局定义,我们就需要用到namespace。

当我们用ts定义一个变量或者函数

js
let a=1 class B { }

在编译后,他会被定义到全局

js
var a = 1; var B = /** @class */ (function () { function B() { } return B; }());

这显然并不是我们想看到的,因为他污染了全局变量。 我们可以这样做,使用namespace申明一个Home变量(全局),使用export导出变量。这样我们就可以通过 Home.c访问到变量,Home.a和Home.B无法进行访问,因为它们没有进行导出

ts
namespace Home { let a=1 class B { } export let c=100 }

reference

配合namespace使用

.tsconfig.json

json
"compilerOptions": { "module": "amd", "outFile": "./build/cs.js", }

可以使用outFile将多个文件打成一个文件。 如果此时文件存在引用关系的话,则需要reference来定义执行顺序, 否则a文件引用b文件,a文件却先执行,这样代码逻辑就会出现问题。

ts
///<reference path='./cs.ts'/> namespace Home { export let a=10 }

使用reference,提前加载cs.ts,保证执行顺序

   

本文作者:BARM

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!