本文最后更新于 2021年4月4日 晚上
Typescript 语言简介, 以学习 React 开发.
有如下两种方式可以执行 ts 文件:
- 用 ts-node 来执行相关的文件.
- 用 npm 初始化, 然后 npm start 的方式.
基本数据类型
- boolean
- number
- bigint
- array
- tuple
- enum
- any
- void
- undefined
- null
- never
特殊类型: object, 推测在 ts 中表示可选类型是这样的: (可空的类型 | null
)
类型转换
使用 as
进行数据类型转换.
接口
1 2 3 4 5 6 7
| interface LabeledObject { label: string }
function printLabelWith(obj: LabeledObject) { console.log(obj.label) }
|
接口可以定义可选的属性.
类
类的简单定义如下所示:
1 2 3 4 5 6 7 8 9 10 11
| class Greeter { greeting: string; constructor(message: string) { this.greeting = message; } greet() { return "Hello, " + this.greeting; } }
let greeter = new Greeter("world");
|
其中构造方法使用 constructor
, 另外方法不需要添加 function
来修饰. 在 ts 中新建对象仍然使用 new 关键字.
继承的写法如下:
1 2 3 4 5 6 7 8 9 10 11
| class Animal { move(distanceInMeters: number = 0) { console.log(`Animal moved ${distanceInMeters}m.`); } }
class Dog extends Animal { bark() { console.log('Woof! Woof!'); } }
|
另外方法的覆盖直接写同名方法即可, 不需要添加 override, 这个和 oc 的语法类似:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Animal { name: string; constructor(theName: string) { this.name = theName; } move(distanceInMeters: number = 0) { console.log(`${this.name} moved ${distanceInMeters}m.`); } }
class Snake extends Animal { constructor(name: string) { super(name); } move(distanceInMeters = 5) { console.log("Slithering..."); super.move(distanceInMeters); } }
class Horse extends Animal { constructor(name: string) { super(name); } move(distanceInMeters = 45) { console.log("Galloping..."); super.move(distanceInMeters); } }
|
属性或方法如果没有添加访问修饰, 则默认是 public
的, 在 ts 中有 public/private/protected 三种访问修饰.
在类中仍然可以拥有 static 属性.
在 ts 中可以声明抽象类, 使用 abstract
语法.
在 ts 中还可以使用 class 作为接口的父接口使用, 这个类似 dart 中使用 class 作为接口的用法:
1 2 3 4 5 6 7 8 9 10
| class Point { x: number; y: number; }
interface Point3d extends Point { z: number; }
let point3d: Point3d = {x: 1, y: 2, z: 3};
|
泛型
泛型工厂方法的实现: 居然可以这样来避免外部直接使用 new, 而且是泛型的
1 2 3
| function create<T>(c: {new(): T; }): T { return new c(); }
|
更复杂的例子可以是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class BeeKeeper { hasMask: boolean; }
class ZooKeeper { nametag: string; }
class Animal { numLegs: number; }
class Bee extends Animal { keeper: BeeKeeper; }
class Lion extends Animal { keeper: ZooKeeper; }
function createInstance<A extends Animal>(c: new () => A): A { return new c(); }
createInstance(Lion).keeper.nametag; createInstance(Bee).keeper.hasMask;
|
模块(Module)
模块是独立的程序单元, 在其中的类, 对象, 变量不会被暴露在全局范围, 除非使用 export
显式暴露. 使用者通过 import
语法来使用被 export 的内容.
在 TS/JS 中, 如果顶层包含 import/export 的文件, 就认为是一个 module.
不包含 import/export 的就认为是脚本, 它里面的内容是全局的.
export 的语法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| export const numberRegexp = /^[0-9]+$/;
export class ZipCodeValidator implements StringValidator { isAcceptable(s: string) { return s.length === 5 && numberRegexp.test(s); } }
class ZipCodeValidator implements StringValidator { isAcceptable(s: string) { return s.length === 5 && numberRegexp.test(s); } } export { ZipCodeValidator }; export { ZipCodeValidator as mainValidator };
export class ParseIntBasedZipCodeValidator { isAcceptable(s: string) { return s.length === 5 && parseInt(s).toString() === s; } }
export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";
export * from "./StringValidator"; export * from "./ZipCodeValidator"; export * from "./ParseIntBasedZipCodeValidator";
|
import 的语法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
import { ZipCodeValidator } from "./ZipCodeValidator";
let myValidator = new ZipCodeValidator();
import { ZipCodeValidator as ZCV } from "./ZipCodeValidator"; let myValidator = new ZCV();
import * as validator from "./ZipCodeValidator"; let myValidator = new validator.ZipCodeValidator();
import "./my.css";
|
另外每个模块都可以包含唯一的 export default
:
1 2 3 4 5 6 7 8 9 10
| export default class ZipCodeValidator { static numberRegexp = /^[0-9]+$/; isAcceptable(s: string) { return s.length === 5 && ZipCodeValidator.numberRegexp.test(s); } }
import validator from "./ZipCodeValidator";
let myValidator = new validator();
|
名字空间
在 ts 中可以使用和 cs 类似的名字空间的概念. 通过名字空间来组织代码, 另外还可以将一个名字空间分布到多个文件中, 只需要添加 reference tag:
Validation.ts:
1 2 3 4 5
| namespace Validation { export interface StringValidator { isAcceptable(s: string): boolean; } }
|
LettersOnlyValidator.ts:
1 2 3 4 5 6 7 8 9
| namespace Validation { const lettersRegexp = /^[A-Za-z]+$/; export class LettersOnlyValidator implements StringValidator { isAcceptable(s: string) { return lettersRegexp.test(s); } } }
|
ZipCodeValidator.ts:
1 2 3 4 5 6 7 8 9
| namespace Validation { const numberRegexp = /^[0-9]+$/; export class ZipCodeValidator implements StringValidator { isAcceptable(s: string) { return s.length === 5 && numberRegexp.test(s); } } }
|
需要认识到名字空间和 module 是两种不同的模块组织形式.