TypeScript 是一种由微软开发的开源编程语言,它是 JavaScript 的超集,提供了静态类型检查、面向对象编程、泛型等高级特性,可以使 JavaScript 代码更加可读、可维护和可扩展。随着 TypeScript 在前端开发中的广泛应用,学习 TypeScript 已经成为了前端开发者必不可少的技能之一。
单值定义
tsclass Animal {
move(distance:number=0){
console.log(`Animal moved ${distance}m`)
}
}
对象定义
tsclass Animal {
move(obj:{a:string,b:number}={a:'1',b:2}){
console.log(`Animal moved ${obj.a}${obj.b}m`)
}
}
super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B的实例。
因此super()在这里相当于A.prototype.constructor.call(this)。
super.move()相当于A.prototype.move.call(this)。
tsclass 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)
兼容性:存取器要求你将编译器设置为输出 ECMAScript 5 或更高。
不支持降级到 ECMAScript 3。
因为使用到了Object.defineProperty这个API
命令:
shelltsc --target es5 index.ts
tsclass 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
tsclass Animal {
public name: string // => name: string效果一致
public constructor(name: string) {
this.name = name
}
}
new Animal('wain').name // 可以被访问到
不可以被实例化访问,不可以被extends继承,完全私有
tsclass Animal {
private name: string
constructor(name: string) {
this.name = name
}
}
new Animal('Cat').name // ERROR: 'name' 是私有的.
不可以被实例化访问,可以被extends继承
tsclass Animal {
private name: string
protected constructor(name: string) {
this.name = name
console.log('s1')
}
}
let a=new Animal('1') // 无法被初始化,因为constructor是受保护的
abstract 关键字是用于定义抽象类和在抽象类内部定义抽象方法。
抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。不同于接口,抽象类可以包含成员的实现细节。
tsabstract 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 当做类型的一部分使用,而不是整个类型,增加了灵活性。
tsfunction 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'])
方式一:
tsfunction identity<T>(arg: T): T {
return arg
}
let myIdentity: <T>(arg: T) => T = identity
方式二:对象字面量来定义泛型函数
tsfunction identity<T>(arg:T):T {
return arg
}
let myIdentity:{<T>(arg:T):T}=identity
方式三:泛型接口
tsinterface GenericIdentityFn<T>{
(arg:T):T
}
function identity<T>(arg:T):T {
return arg
}
let myIdentity:GenericIdentityFn<number []>=identity
约束必须存在的字段类型
tsinterface 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
约束字段需要存在于对象中
tsfunction 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
tsclass 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)[]
tsclass Animal {
numLegs: number
}
class Bee extends Animal {}
class Lion extends Animal {}
let zoo = [new Bee(), new Lion()]
tswindow.onmousedown=function(mouseEvent){
console.log(mouseEvent.clickTime) // ERROR,TS会自己进行上下文推断
}
// 解决问题:
window.onmousedown=function(mouseEvent:any){
console.log(mouseEvent.clickTime)
}
返回键值的联合类型
tsenum 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的联合类型
在ts中,额外的功能点是返回当前值的接口类型
tsenum 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的接口类型
定义的类型只会用于编译时的检查,编译结果中会被删除
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
commonjs模式下,定义变量和函数会在全局定义。这个时候,我们不想变量在全局定义,我们就需要用到namespace。
当我们用ts定义一个变量或者函数
jslet a=1
class B {
}
在编译后,他会被定义到全局
jsvar a = 1;
var B = /** @class */ (function () {
function B() {
}
return B;
}());
这显然并不是我们想看到的,因为他污染了全局变量。 我们可以这样做,使用namespace申明一个Home变量(全局),使用export导出变量。这样我们就可以通过 Home.c访问到变量,Home.a和Home.B无法进行访问,因为它们没有进行导出
tsnamespace Home {
let a=1
class B {
}
export let c=100
}
配合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 许可协议。转载请注明出处!