// 基础类型
// 布尔值
let isDonen: boolean = false;
console.log('布尔值:', isDonen);
// 数字类型
let decLiteral: number = 6;
console.log('数字类型:', decLiteral);
// 字符串
let nameStr: string = "bob";
nameStr = "smith";
console.log('字符串:', nameStr);
// 数组
let listArr: number[] = [1, 2, 3];
let ligsArr: Array<number> = [2, 3, 4];
console.log('数组:', listArr, '==>>', ligsArr);
// 元组 Tuple(元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同)
let tupArr: [string, number];
tupArr = ['23', 34];
console.log('元组:', tupArr);
// 枚举(枚举类型可以为一组数值赋予友好的名字。)
enum Color1 { Red, Green, Blue }
let c: Color1 = Color1.Green;
console.log('枚举:', Color1);
//枚举类型提供的一个便利是你可以由枚举的值得到它的名字。 例如,我们知道数值为2,但是不确定它映射到Color里的哪个名字,
enum Color { Red = 1, Green, Blue };
let colorName: string = Color[2];
console.log('colorName:', colorName);
// Any (在不知道变量属于上述什么类型的时候,可以定义为Any类型)(在对现有代码进行改写的时候,any类型是十分有用的,它允许你在编译时可选择地包含或移除类型检查)
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
let listArrAny: any[] = [1, true, "free"];
console.log('Any:', notSure, listArrAny);
// Void 当一个函数没有返回值的时候
function TEST(name: string): void {
console.log('Void', name)
}
// 声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined和null
let nuTEst: void = null;
// Null 和 Undefined(undefined和null两者各自有自己的类型分别叫做undefined和null)
// Never(never类型表示的是那些永不存在的值的类型)
// 返回never的函数必须存在无法达到的终点
function errorNever(message: string): never {
throw new Error(message);
}
console.log('errorNever', '返回never的函数必须存在无法达到的终点')
// Object object表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型。
/**
* @title 类型断言
* @desc 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构
* @result 它没有运行时的影响,只是在编译阶段起作用
* @method 1. <> 2. as
*/
// 用法一
let someValue: any = '我是一个字符串';
// 在这里将someValue的 'any' 类型, 转换为 'string' 类型, 使用 '<>'语法
let lenStr: number = (<string>someValue).length;
// 进行类型转换 使用as语法
let lenStr1: number = (someValue as string).length;
// ts 类
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
/**
* @class Animal
* @public 公共变量(在当前类和派生的子类中都可以使用)
* @private 私有变量(不能在声明它的类的外部访问 只能在当前类中使用)
* @protected 受保护的(可以在当前类和派生类中使用,当构造函数使用protected修饰的时候 该类只能被继承)
*/
class Animal {
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}m.`);
}
}
class Dog extends Animal {
bark() {
console.log('Woof! Woof!');
}
}
const dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();
class AnimalNew {
// 在TS类中 属性 方法 构造函数 默认使用public
public name: string;
private age: number; // 当成员被标记成 private时,它就不能在声明它的类的外部访问 只能在当前类中使用
protected email: string;
public constructor(theName: string, age?: number) {
this.name = theName;
this.age = age;
}
public move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.age is ${this.age}`);
}
}
// 属性值 xdfc 只能访问 name 和 move
const xdfc = new AnimalNew('zyn', 78);
// xdfc.age 是不可以访问的
class Persin extends AnimalNew {
public constructor(name: string, age?: number) {
super(name, age);
}
public getElevatorPitch() {
// 访问父类 受保护的属性 email 和 公共的属性 name 但是不可以访问 age(私有变量)
return `Hello, my name is ${this.name} and I work in ${this.email}.`;
}
}
const persinH = new Persin('ok');
// 创建只能被继承的类
class Quanyecha {
protected name: string;
static obj: object = { age: 45 };
protected constructor(name: string) {
this.name = name;
}
public say() {
// 调用当前类中的静态方法 和属性
Quanyecha.goodSay();
}
private sayPri() { }
protected sayPro() { }
static goodSay(): object {
return Quanyecha.obj;
}
}
class Shashengwan extends Quanyecha {
public constructor(name: any) {
super(<string>name) // 使用断言转换类型
}
public init() {
this.makeinstall();
}
private makeinstall() {
Quanyecha.goodSay(); // 子类中访问父类的静态方法
this.say(); // 访问父类中的 公共方法
this.sayPro(); // 访问父类中的 受保护的方法 只能在子类的内部使用
console.log(`${this.name}`) // 访问 父类中的 受保护的属性
}
}
// 上述类 构造函数使用了(protected)修饰不能直接使用 new 实例化该类
// const ali = new Quanyecha('') // error 类“Quanyecha”的构造函数是受保护的,仅可在类声明中访问。
const xiejian = new Shashengwan('anj');
xiejian.init(); // xiejian 只能调用 子类 和父类中的 public 修饰的属性和方法
xiejian.say();
// readonly修饰符 ( 只读属性必须在声明时或构造函数里被初始化。)
class Octopus {
readonly name: string;
readonly numberOfLegs: number = 8; // 声明时 初始化
constructor(theName: string) {
this.name = theName; // 在构造函数中初始化
}
}
let dad = new Octopus("Ma");
console.log(`只能读取属性不能进行在赋值的操作:${dad.name},${dad.numberOfLegs}`);
// 可以借助 readonly 将构造函数中的声明和赋值简写
class Octopus1 {
constructor(readonly name: string) { }
}
let dad1 = new Octopus1("Ma");
console.log(dad1.name) //
// 存取器
class Employee {
fullName: string;
}
// 下面 展示 实例对象可以随意修改 public 修饰的属性的值,
let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
console.log(employee.fullName);
}
let passcode = "secret passcode";
class Employee1 {
private _fullName: string;
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
if (passcode && passcode == "secret passcode") {
this._fullName = newName;
}
else {
console.log("Error: Unauthorized update of employee!");
}
}
}
let employee1 = new Employee1();
employee1.fullName = "Bob Smith";
if (employee1.fullName) {
alert(employee1.fullName);
}
// 抽象类 (抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化)
abstract class Department3 {
constructor(public name: string) {
}
printName(): void {
console.log('Department name: ' + this.name);
}
abstract printMeeting(): void; // 必须在派生类中实现
}
class AccountingDepartment extends Department3 {
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: Department3; // 允许创建一个对抽象类型的引用
// department = new Department(); // 错误: 不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
// department.generateReports(); // 错误: 方法在声明的抽象类中不存在
// 把类当做接口使用
class Point {
x: number;
y: number;
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = { x: 1, y: 2, z: 3 };
// ts 装饰器
// 随着TypeScript和ES6里引入了类,在一些场景下我们需要额外的特性来支持标注或修改类及其成员
// 装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上
// expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。
function color(value: string) { // 这是一个装饰器工厂
return function (target) { // 这是装饰器
// do something with "target" and "value"...
}
}
/// 装饰器 demo
function f() {
// 装饰器需要返回一个函数
console.log(`f(), index = 1`);
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(`f(), index = 2`);
}
}
function g() {
console.log(`g(), index = 1`);
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(`g(), index = 2`);
}
}
class DECTEST {
@f()
@g()
method() { }
}
/// 类装饰器
/**
* 类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。 类装饰器不能用在声明文件中( .d.ts),也不能用在任何外部上下文中(比如declare的类)
* 类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
*/
// 创建一个类@sealed装饰器
/// 会将使用该装饰器的类的构造函数传入
function sealed(constructor: Function) {
//console.log('类装饰器输出参数:', constructor) // function GreeterOK(message) { this.greeting = message;}
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed // 当@sealed被执行的时候,它将密封此类的构造函数和原型
class GreeterOK {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
const Zyn = new GreeterOK('test');
Zyn.greet();
function classDecorator<T extends { new(...args: any[]): {} }>(constructor: T) {
console.log(typeof constructor, 'T')
return class extends constructor {
newProperty = "new property";
hello = "override";
}
}
@classDecorator
class Greeter5 {
property = "property";
hello: string;
constructor(m: string) {
this.hello = m;
}
}
const QQ = new Greeter5("world")
console.log(QQ.hello, QQ.property);
// 方法装饰器
/**
* 它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义
* 方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
* 1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
* 2.成员的名字。
* 3.成员的属性描述符。
* 注意 如果代码输出目标版本小于ES5,属性描述符将会是undefined。
* 如果方法装饰器返回一个值,它会被用作方法的属性描述符。
**/
/**
* @param {boolean} value
* @returns function
*/
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(target, propertyKey, descriptor, value);
if (descriptor) {
descriptor.enumerable = value;
}
}
}
class Greeter9 {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}
}
const kk9 = new Greeter9('enm')
console.log(kk9.greet());
// 属性装饰器
/**
* 1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
* 2.成员的名字。
*/
// import * as Reflect from "reflect-metadata";
const formatMetadataKey = Symbol("format");
function format(formatString: string) {
return Reflect.metadata(formatMetadataKey, formatString);
}
function getFormat(target: any, propertyKey: string) {
return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}
// ts 枚举 TypeScript支持数字的和基于字符串的枚举。
/**
* @enum {number}
* @des Up使用初始化为 1。 其余的成员会从 1开始自动增长 Direction.Up的值为 1, Down为 2, Left为 3, Right为 4。
*/
enum Direction {
Up = 1,
Down,
Left,
Right
}
// 默认不使用初始化的时候 下标默认从0 开始
enum Direction1 {
Up,
Down,
Left,
Right,
}
enum Responsec {
No = 0,
Yes = 1
}
function respond(recipient: string, message: Responsec): void {
// ...
console.log(`recipient: ${recipient}, message:${message}`)
}
respond("Princess Caroline", Responsec.Yes)
console.log(`Direction1: ${Direction1.Up}`);
console.log(`Direction: ${Direction.Up}`);
console.warn('=======字符串枚举========>>>>>')
// 字符串枚举
enum Direction3 {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
console.log(`Direction3:${Direction3.Up}`);
console.warn('=======异构枚举(字符串和数字混合)======>>>')
// 下面的方式可以但是不推荐
enum BooleanLikeHeterogeneousEnum {
No = 0,
Yes = "YES",
}
// 类型推论 即,类型是在哪里如何被推断的。
// 量x的类型被推断为数字。 这种推断发生在初始化变量和成员,设置默认参数值和决定函数返回值时
let x = 3;
class AnimalType {
// readonly name: string 会默认初始化 name => this.name = name;
protected constructor(protected readonly name: string) { }
protected say() {
console.log(`AnimalType say: ${this.name}`)
}
}
class Rhino extends AnimalType {
constructor(protected name: string) {
super(name);
}
public stratSay() {
super.say();
this.say();
}
}
class GOD {
}
const nj = new Rhino('gogo');
nj.stratSay()
const zoo: AnimalType[] = [new Rhino('yu')];
// 类型兼容性
interface Named {
name: string;
}
class Person {
name: string;
}
let p: Named;
// OK, because of structural typing
p = new Person();
let isDone: boolean = false;
let list: Array<number> = [4, 2, 3];
let isstr: Array<string> = ['33', '']
console.log(isDone)
interface Person {
name: string,
age: number
}