tsc --init
生成 tsconfig.json 改 "outdir": "./js"
tsconfig.json
TS 中为了使编写的代码更加规范,更有利于维护,增加了类型校验,在 TS 中主要提供了以下数据类型
数组类型
元组类型
枚举类型(enum)
随着计算机的不断普及,程序不仅只用于数值计算,还更广泛地用于处理非数值的数据。
例如性别、年龄、月份、颜色等,都不是数值数据。
在其它程序中用自然语言中有相应含义的单词来代表某一状态,则程序就很容易阅读和理解。
也就是说,实现考虑到某一变量可能取的值,尽量用自然语言中含义清楚的单词来表示它的每一个值。
这种方法成为枚举方法,用这种方法定义的类型称枚举类型。
enum 枚举名 {
标识符[=整型常数],
标识符[=整型常数],
...
标识符[=整型常数],
}
enum Color {
blue,
red = 30,
'orange'
};
let a: Color = Color.blue
console.log(a) // 0
let b: Color = Color.red
console.log(b) // 30
let c: Color = Color.orange
console.log(c) // 31
任意类型
let oBox: any = document.getElementById('box');
oBox.style.color = 'red';
// oBox 不指定类型或者指定 Object 类型都会报错,所以需要指定 any 类型。
null 和 undefined
let num1: undefined;
console.log(num1);
let num2: number | undefined
num2 = 123
console.log(num2)
void 类型
ts function run(): void { console.log("ok") } //表示 run 函数没有返回值
Never 类型
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {
}
}
function run(): string {
return 'abc'
}
function getInfo(name: string, age?: number) {
if(age) {
return `${name} --- ${age}`
} else {
return `${name} --- 年龄保密`
}
}
alert(getInfo("张三"))
function getInfo(name: string, age: number = 20) {
if(age) {
return `${name} --- ${age}`
} else {
return `${name} --- 年龄保密`
}
}
alert(getInfo("张三"))
function sum(...result: number[]): number {
let sum = 0
result.forEach(item => {
sum += item
})
return sum
}
alert(sum(1, 2, 3, 4))
function getInfo(name: string): string;
function getInfo(age: number): number;
function getInfo(str: any): any {
if(typeof str === 'string') {
return '我叫:' + str;
} else {
return '我的年龄是:' + str
}
}
function Person(name, age) {
this.name = name;
this.age = age;
this.run = function () {
alert(this.name + "在运动")
}
}
Person.prototype.sex = "男"
Person.prototype.work = function() {
alert(this.name + "在工作")
}
function Web(name, age) {
// 对象冒充实现继承构造函数的属性和方法
Person.call(this, name, age)
}
// 实现继承其原型链上的属性和方法 - 下面两种方式都可以实现
// Web.prototype = new Person()
Web.prototype = Person.prototype
var w = new Web("张三");
w.run()
w.work()
class Person {
name: string;
constructor(name: string) {
this.name = name
}
run():void {
alert(this.name)
}
}
class Person {
name: string;
constructor(name: string) {
this.name = name
}
run():void {
alert(`${this.name}在运动`)
}
}
class Web extends Person {
constructor(name: string) {
// 初始化父类的构造函数
super(name)
}
work() {
alert(`${this.name}在工作`)
}
}
class Person {
public name: string;
public age: number = 20;
static sex = "男"
constructor(name: string) {
this.name = name
}
run() {
alert(`${this.name}在运动`)
}
work() {
alert(`${this.name}在工作`)
}
// 静态方法 里面无法直接调用类里面的属性
static print() {
// alert("print方法" + this.age)
alert("print方法" + Person.sex)
}
}
Person.print()
class Animal {
name: string;
constructor(name: string) {
this.name = name
}
eat() { // 具体吃什么,不知道,继承它的子类去实现,每一个子类的表现不一样
console.log("吃的方法")
}
}
class Dog extends Animal {
constructor(name: string) {
super(name)
}
eat() {
return this.name + '吃粮食'
}
}
class Cat extends Animal {
constructor(name: string) {
super(name)
}
eat() {
return this.name + '吃老鼠'
}
}
abstract class Animal {
public name: string;
constructor(name: string) {
this.name = name
}
abstract eat(): any; // 抽象方法不包含具体实现并且必须在派生类中实现
}
class Dog extends Animal {
constructor(name: string) {
super(name)
}
// 抽象类的子类必须实现抽象类里面的抽象方法
eat() {
return this.name + '吃粮食'
}
}
class Cat extends Animal {
constructor(name: string) {
super(name)
}
// 抽象类的子类必须实现抽象类里面的抽象方法
// 不包含 eat 抽象方法,所以报错了
// 非抽象类“Cat”不会实现继承自“Animal”类的抽象成员“eat”。
}
// let a = new Animal() // 不能这样用
let dog = new Dog("大黄")
alert(dog.eat())
接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里,接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里的方法的实现细节,它之规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。Typescript 中的接口类似于 Java,同事还增加了更加灵活的接口类型,包括属性、函数、可索引和类等。
function printLabel(label: string): void {}
printLabel("哈哈")
function printLabel(labelInfo: {label: string}): void {}
printLabel("哈哈") // 错误写法
printLabel({label: "哈哈"}) // 正确写法
interface FullName {
firstName: string;
secondName: string;
}
function printName(name: FullName) {
// 必须传入对象 firstName 和 secondName
console.log(name.firstName + '---' + name.secondName)
}
interface FullName {
firstName: string;
secondName?: string;
}
interface encrypt {
(key: string, value: string): string
}
let run: encrypt = function(key: string, value: string): string {
return key + value
}
interface UserArr {
[index: number]: string;
}
let arr: UserArr = ['123', 'bbb']
console.log(arr[0])
interface UserObj {
[index: string]: string;
}
let obj: UserObj = {name: '张三'}
console.log(obj.name)
interface Animal {
name: string;
eat(str: string): void
}
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name
}
eat() {
console.log(this.name + '吃肉')
}
}
interface Animal {
eat(): void;
}
interface Person extends Animal {
work(): void;
}
class Programmer {
public name: string;
constructor(name: string) {
this.name = name
}
coding(code: string) {
console.log(this.name + code)
}
}
class Web extends Programmer implements Person {
constructor(name: string) {
super(name)
this.name = name
}
eat() {
console.log(this.name + '吃馒头')
}
work() {
console.log(this.name + '写代码')
}
}
let w = new Web("小黑")
w.eat()
w.work()
w.coding("写 TS 代码")
泛型:软件工程中,我们不仅要创建一直的定义良好的 API,同时也要考虑可重用性。组件不仅能够支持当前的数据类型,同事也能支持未来的数据类型,着在创建大型系统时为你提供十分灵活的功能。
在像 C# 和 Java 这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。这样用户就可以以自己的数据类型来使用组件。
通俗理解:泛型就是解决类 接口 方法的复用性、以及对不特定类型的支持。
function getData(value: T):T {
return value
}
getData(123)
class MinClass {
public list: T[] = []
add(value: T):void {
this.list.push(value)
}
min():T {
let minNum = this.list[0];
for(let i = 0; i < this.list.length; i++) {
if (minNum > this.list[i]) {
minNum = this.list[i]
}
}
return minNum
}
}
let m1 = new MinClass();
m1.add(1)
m1.add(14)
m1.add(5)
alert(m1.min())
interface ConfigFn {
(value: T): T
}
function getData(value: T):T {
return value
}
var myGetData:ConfigFn = getData;
myGetData('20')
// myGetData(20) // 错误
// getData('1234') // 错误·ts
class ArticleCate {
title: string | undefined;
desc: string | undefined;
status: number | undefined;
constructor(params: {
title: string | undefined,
desc: string | undefined,
status?: number |undefined,
}) {
this.title = params.title
this.desc = params.desc
this.status = params.status
}
}
class MysqlDb {
add(info: T):boolean {
console.log(info)
return true
}
updated(id: number, info: T): boolean {
console.log(info)
return true
}
}
// 添加操作
let a = new ArticleCate({
title: "分类",
desc: '123',
})
let db = new MysqlDb()
db.add(a)
// 修改操作
let b = new ArticleCate({
title: "分类2",
desc: '456',
status: 1,
})
db.updated(123, b)
功能:定义一个操作数据库的库,支持 Mysql、Mssql、MongDB
要求1:Mysql、Mssql、MongDB 功能一样,都有 add、update、delete、get 方法
注意:约束统一的规范,以及代码重用
解决方案:需要约束规范所以要定义接口,需要代码重用所以用到泛型
1、接口:在面向对象的编程中,接口是一种规范
2、泛型 通俗理解:泛型就是解决类 接口 方法的复用性
interface DBI {
add(info: T): boolean;
update(info: T, id: number): boolean;
delete(id: number): boolean;
get(id: number): any[];
}
// 定义一个操作 mysql 数据库的类 注意:要实现泛型接口,这个类也应该是一个泛型
class MysqlDb implements DBI {
constructor() {
console.log("数据库建立连接")
}
add(info: T): boolean {
console.log(info)
return true
}
update(info: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(id: number): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
let list = [
{
title: 'xxxx',
desc: 'xxxxx',
},
{
title: 'xxxx',
desc: 'xxxxx',
},
]
return list
}
}
// 定义已个操作 mssql 数据库的类
class MssqlDb implements DBI {
add(info: T): boolean {
console.log(info)
return true
}
update(info: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(id: number): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
throw new Error("Method not implemented.");
}
}
// 操作用户表 定义一个 User 类和数据表做映射
class User {
username: string | undefined;
password: string | undefined;
}
let u = new User()
u.username = "张三"
u.password = "123456"
let oMysql = new MysqlDb()
oMysql.add(u)
let oMssql = new MssqlDb();
oMssql.add(u)
// 获取 User 表 id 为4的数据
let data = oMysql.get(4)
console.log(data)
namespace A {
interface Animal { }
export class Cat {
eat() {}
}
}
let a = new A.Cat()
类装饰器在类声明之前被声明(紧靠着类声明)。类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。传入一个参数
function logClass(params: any) {
console.log(params)
// params 就是当前类
params.prototype.apiUrl = 'xxx'
params.prototype.run = function() {
console.log("我是一个 run 方法")
}
}
@logClass
class HttpClient {
constructor() {}
getData() {}
}
let http = new HttpClient()
console.log(http.apiUrl)
http.run()
function logClass(params: string) {
return function(target: any) {
console.log(target)
console.log(params)
target.prototype.apiUrl = params
}
}
@logClass('hello')
class HttpClient {
constructor() {}
getData() {}
}
let http = new HttpClient()
console.log(http.apiUrl)
function logClass(target: any) {
console.log(target)
return class extends target {
apiUrl: any = '我是修改后的数据'
getData() {
this.apiUrl = this.apiUrl + '----'
console.log(this.apiUrl)
}
}
}
@logClass
class HttpClient {
public apiUrl: string | undefined;
constructor() {
this.apiUrl = "我是构造函数中的 apiUrl"
}
getData() {
console.log(this.apiUrl);
}
}
let http = new HttpClient()
http.getData()
// 类装饰器
function logClass(params: string) {
return function(target: any) {
// console.log(params)
// console.log(target)
}
}
// 属性装饰器
function logProperty(params: any) {
return function(target: any, attr: any) {
console.log(params)
console.log(target)
console.log(attr)
target[attr] = params
}
}
@logClass('xxx')
class HttpClient {
@logProperty('http://itying.com')
public url: any | undefined;
constructor() {
}
getData() {
console.log(this.url)
}
}
let http = new HttpClient()
http.getData()
function get(params: any) {
return function(target: any,methodName: any, desc: any) {
console.log(target)
console.log(methodName)
console.log(desc)
target.apiUrl = 'xxx'
target.run = function () {
console.log('run')
}
}
}
class HttpClient {
public url: any | undefined;
constructor() {}
@get('http://itying.com')
getData() {
console.log(this.url)
}
}
let http = new HttpClient()
console.log(http.url)
http.run()
function get(params: any) {
return function(target: any,methodName: any, desc: any) {
console.log(target)
console.log(methodName)
console.log(desc.value)
// 修改装饰器的方法 把装饰器方法里面传入的所有参数改为 string 类型
// 1. 保存当前方法
let oMethod = desc.value
desc.value = function(...args:any[]) {
args = args.map((value) => {
return String(value)
})
console.log(args)
oMethod.apply(this, args)
}
}
}
class HttpClient {
public url: any | undefined;
constructor() {}
@get('http://itying.com')
getData(...args:any[]) {
console.log(args)
console.log('getData里面的代码')
}
}
let http = new HttpClient()
http.getData(123, '12333')
```
function logParams(params: any) {
return function(target: any, methodName: any, paramsIndex: any) {
console.log(params)
console.log(target)
console.log(methodName)
console.log(paramsIndex)
target.apiUrl = params
}
}
class HttpClient {
public url: any | undefined;
constructor() {}
getData(@logParams('uuid') uuid: any) {
console.log(uuid)
}
}
let http = new HttpClient()
http.getData(123)
console.log(http.apiUrl)
```
function logClass1(params: string) {
return function(target: any) {
console.log("类装饰器1")
}
}
function logClass2(params: string) {
return function(target: any) {
console.log("类装饰器2")
}
}
function logAttribute(params?: string) {
return function(target: any, attrName: any) {
console.log("属性装饰器")
}
}
function logMethod(params?: string) {
return function(target: any, attrName: any, desc: any) {
console.log("方法装饰器")
}
}
function logParams1(params?: string) {
return function(target: any, attrName: any, desc: any) {
console.log("方法参数装饰器1")
}
}
function logParams2(params?: string) {
return function(target: any, attrName: any, desc: any) {
console.log("方法参数装饰器2")
}
}
@logClass1("http://www.itying.com/api")
@logClass2("xxxx")
class HttpClient {
@logAttribute()
public apiUrl: string | undefined
constructor() {
}
@logMethod()
getData() {
return true
}
setData(@logParams1() attr1:any, @logParams2() attr2:any) {}
}
let http = new HttpClient()
// 输出顺序:属性装饰器 方法装饰器 方法参数装饰器2 方法参数装饰器2 类装饰器2 类装饰器1