day134:2RenMJ:TypeScript的抽象类&装饰器&命名空间&模块&编译配置文件&python中的类型注解
目录
1.抽象类
抽象类(abstract class)做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口,抽象类可以包含成员的实现细节。 abstract
关键字是用于定义抽象类和在抽象类内部定义抽象方法。
// 抽象父类 abstract class Animal{ abstract makeSound(): void; // 抽象方法,没有函数体 constructor(public name: string){ // 抽象类的构造方法 } desc(): void { // 抽象类中也可以定义子类的公共方法或公共属性 console.log('roaming the earch...'); } } // 抽象子类 abstract class Dog extends Animal{ abstract move(): string; } // 具象类/具体类 class ChineseGardenDog extends Dog{ public name:string; makeSound(){ return "汪汪汪~" } move(): string { return "奔跑中...." } constructor(name: string){ super(name); // 继承了抽象类的子类,必须对父类进行初始化 } } var dog = new ChineseGardenDog("来福"); console.log(dog.name); console.log(dog.makeSound());
2.装饰器
function derator1() { console.log("derator1(): evaluated"); return function (target, propertyKey: string, descriptor: PropertyDescriptor) { console.log("derator1(): called"); } } function derator2(name:string) { console.log(`derator2(): evaluated,name=${name}`); return function (target, propertyKey: string, descriptor: PropertyDescriptor) { console.log(`derator2(): called,name=${name}`); } } class Demo { @derator1() @derator2("xiaoming") show() { console.log("show()执行了") } } var d = new Demo(); d.show(); /* * 输出结果顺序: * derator1(): evaluated * derator2(): evaluated,name=xiaoming * derator2(): called,name=xiaoming * derator1(): called * show()执行了 * */
3.命名空间
当项目大了以后,需要创建和声明的函数,类就多了,自然人也就多了,人多就坏事。想想全国有几个张三?
命名空间(namespace)一个最明确的目的就是解决重名问题。
命名空间定义了标识符的可见范围,一个标识符可在多个名字空间中定义,它在不同名字空间中的含义是互不相干的。这样,在一个新的名字空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其他名字空间中。
1.定义一个命名空间
// 命名空间的名称采用驼峰式写法 namespace App{ // 需要在命名空间外部可以调用 当前命名空间的类,函数和接口等,则需要在左边添加 export 关键字。 // 变量 export var username:string="App空间的变量"; // 常量,一旦定义以后,不能修改值 export const NAME = "App命名空间的常量"; // 函数 export function func(){ return "App命名空间里面的func" } // 类 export class Humen{ } // 当然,在当前命名空间下也是可以执行代码的 }
2.导入命名空间
main.ts,代码:
导入其他命名空间的格式:/// <reference path = "文件名" />
,可以导入多个命名空间,一行一个。
/// <reference path="app.ts" /> console.log(App.func()); // 调用其他命名空间的内容,必须以"命名空间的名称.xxxx"格式进行调用 console.log(App.NAME); console.log(App.username); console.log(new App.Humen());
使用了命名空间以后,编译命令需要稍微调整如下:
tsc --out main.js main.ts # 必须指定--out参数才能正常编译
4.模块
TypeScript 模块的设计理念是可以更换的组织代码。模块是在其自身的作用域里执行,并不是在全局作用域,这意味着定义在模块里面的变量、函数和类等在模块外部是不可见的。
typescript提供了两种模块:内部模块和外部模块
1.内部模块
1.声明模块
app.ts,代码
module App{ export class Humen { desc(){ console.log("hello"); } } export function func(){ console.log("hello, func"); } }
2.调用模块
main.ts,代码
/// <reference path="./app.ts"> var people = new App.Humen(); people.desc(); App.func();
使用了内部模块以后,编译命令和命名空间一样:
tsc --out main.js main.ts
2.外部模块
out.js,代码
class Humen{ uname:string; constructor(uname){ this.uname = uname; } desc() { return `您好,我叫 ${this.uname}`; } } export { Humen }; export { Humen as People };
导入模块,main.ts,代码:
import { Humen, People } from "./Out"; let obj1 = new Humen("小白"); let obj2 = new People("小黑"); obj1.desc(); obj2.desc();
编译命令:
tsc --module es6 main.ts # --module 表示代码中编写模块的规范和标准
5.编译配置文件
基于typescript开发的项目根目录,一般都会存在一个文件,叫tsconfig。这是typescript的编译配置文件。
配置选项:https://www.tslang.cn/docs/handbook/compiler-options.html
tsconfig.json,常用配置项说明,代码:
// 当前配置文件名必须固定是: tsconfig.json // 同时,json文件中不能出现注释的,所以此处的注释仅仅是为了学习,开发中决不能有 { "compilerOptions": { "module": "system", // 项目中编写模块的规范标准 "noImplicitAny": true, // 表达式或声明上有隐含的 any类型时报错 "removeComments": true, // 删除所有注释,除了以 /!*开头的版权信息。 "preserveConstEnums": true, // 保留const和Enums声明 "outDir": "script", // 编译结果保存目录 // "outFile": "../../built/local/tsc.js", // 编译以后输出的文件,一般用不上 "sourceMap": true, // 生成相应的 .map文件 "experimentalDecorators": true, // 启用实验性的ES装饰器 "lib": [ // 编译过程中需要引入的库文件的列表 "es5", "dom", "es2015.promise" ] }, "files": [ // 指定要编译的文件列表, 与include和exclude冲突,开发中,一般使用exclude "main.ts" ] // "include": [ // 指定要编译的文件所在目录 //// "src/**/*", // "./" // ], // "exclude": [ // 指定在编译时排除的文件目录 // "node_modules", // "**/*.spec.ts" // ] }
6.python的类型注解
1.typing模块
自python3.5开始,PEP484为python引入了类型注解(type hints)
-
类型检查,防止运行时出现参数和返回值类型、变量类型不符合。
-
作为开发文档附加说明,方便使用者调用时传入和返回参数类型。
-
该模块加入后并不会影响程序的运行,不会报正式的错误,只有提醒。
pycharm目前支持typing检查,参数类型错误会黄色提示。
2.常用类型
-
-
bool,str: 布尔型,字符串类型
-
List, Tuple, Dict, Set:列表,元组,字典, 集合
-
Iterable,Iterator:可迭代类型,迭代器类型
-
3.基本类型指定
from typing import List,Dict,Tuple,Union # 整型 num:int = 100 # 字符串 data:str = "200" # 布尔值 bo:bool = True # 列表 data_list:List[str] = ["1","2","3"] # 字典 data_dict:Dict[str, str] = {"name":"xiaoming",} # 元组[限制数据和类型] data_tuple:Tuple[int,int,bool] = (1,2,False) # 联合类型[泛型] U1 = Union[str,int] # 只能是字符串或者整形 data_union1:U1 = "20" data_union2:U1 = 200 data_union3:U1 = [1,2,3] # 此处不符合要求,出现黄色提示 def test(a:int, b:str) -> str: print(a, b) return 1000 if __name__ == '__main__': test('test', 'abc') """ 函数test, a:int 指定了输入参数a为int类型, b:str b为str类型, -> str 返回值为str类型。 可以看到, 在方法中,我们最终返回了一个int,此时pycharm就会有警告; 当我们在调用这个方法时,参数a我们输入的是字符串,此时也会有警告; 但非常重要的一点是,pycharm只是提出了警告,但实际上运行是不会报错,毕竟python的本质还是动态语言 """
4.复杂的类型标注
from typing import List Vector = List[float] def scale(scalar: float, vector: Vector) -> Vector: return [scalar * num for num in vector] # 类型判定: 传递进行的数据只要类似Vector格式即可,这里也是鸭子类型所导致的. new_vector = scale(2.0, [1.0, -4.2, 5.4])
from typing import Dict, Tuple, Sequence ConnectionOptions = Dict[str, str] Address = Tuple[str, int] Server = Tuple[Address, ConnectionOptions] def broadcast_message(message: str, servers: Sequence[Server]) -> None: ... # The static type checker will treat the previous type signature as # being exactly equivalent to this one. def broadcast_message( message: str, servers: Sequence[Tuple[Tuple[str, int], Dict[str, str]]]) -> None: ... ): ... """ 这里需要注意,元组这个类型是比较特殊的,因为它是不可变的。 所以,当我们指定Tuple[str, str]时,就只能传入长度为2, 并且元组中的所有元素都是str类型 """
5.泛型指定
from typing import Sequence, TypeVar T = TypeVar('T') # 定义泛型变量,可以是任意类型的数据 b2:T = True # b2的值可以是任意类型数据 def first(l: Sequence[T]) -> T: # Generic function return l[0] A = TypeVar('A', bool, str, bytes) # 定义当前泛型的范围只能是字符串或者bytes类型 b3:A = "hello" b4:A = "hello".encode() b5:A = True
6.创建变量时的类型指定
from typing import NamedTuple class Employee(NamedTuple): name: str id: int = 3 employee = Employee('Guido') assert employee.id == 3
7.
from typing import List def test(b: List[int]) -> str: print(b) return 'test' if __name__ == '__main__': test([1, 'a']) """ 从这个例子可以看出来,虽然我们指定了List[int]即由int组成的列表, 但是,实际中,只要这个列表中存在int(其他的可以为任何类型),就不会出现警告 """