TypeScript学习笔记

基础类型

以冒号开头后跟类型名称.

let isDone: boolean = false;
let num: number = 6;
let color: string = "blue";
let list: number[] = [1, 2, 3];
let list2: Array<number> = [1, 2, 3];

集合是特殊的数组类型, 它允许不同类型的元素存在于同一个数组中:

let x: [string, number]
x = ["hello", 10]
x[3] = "world"
// [ 'hello', 10, , 'world' ]
console.log(x)

枚举类型:

enum Color {Red, Green, Blue}
let c: Color = Color.Green
// 1
console.log(c)

通用类型any:

let notSure: any = 4
notSure = 'hello'

let list: any[] = [1, true, 'free']
list[1] = 100

void: 在声明函数则代表无返回值; 声明变量则代表只能赋值undefined, null

function warnUser(): void {
    //
}

let unusable: void = undefined;

null和undefined: 一般很少使用, 直接用any即可. 如果非要声明变量为undefined, null, 也可直接使用void:

let u: undefined = undefined;
let n: null = null;

类型转换:

let someValue: any = 'this is a string'
let strLength: number = (<string>someValue).length
let strLength1: number = (someValue as string).length

 

变量声明

var不推荐使用, 因为ES5中没有块级作用域:

// 10 10 10 10 10 10 10 10 10 10
for (var i = 0; i < 10; i++) {
    setTimeout(() => console.log(i), 100 * i)
}

一般遇到这种情况, 只能修改成如下代码:

// 0 1 2 3 4 5 6 7 8 9
for (var i = 0; i < 10; i++) {
    ((i) => {
        setTimeout(() => console.log(i), 100 * i)
    })(i)
}

let具有块级作用域, 所以用let来替换var.

let语法可用于数组/对象的解析:

let [first, second] = [1, 2]
// 1 2
console.log(first, second)
let [first1, ...rest] = [1, 2, 3, 4]
// 1 [2, 3, 4]
console.log(first1, rest)
let o = {
    a: 'foo',
    b: 12,
    c: 'bar'
}
let {a, b} = o
// foo 12
console.log(a, b)
let {c, ...passthrough} = o
// bar {a: 'foo', b: 12}
console.log(c, passthrough)

也可以指定别名:

let {a: newName1, b: newName2} = o
// equal to
let newName1 = o.a
let newName2 = o.b

也可以指定默认值:

let {a, b = 1001} = o

const专门用于定义常量.

ES6中新引入的"..."用于解构数组或变量:

let first: number[] = [1, 2]
let second: number[] = [3, 4]
let both = [0, ...first, ...second, 5]
// [0, 1, 2, 3, 4, 5]
console.log(both)

let defaults = {a: 1, b: 2}
let search = {...defaults, c: 3}
// { a: 1, b: 2, c: 3 }
console.log(search)

 

接口

编写一个函数, 指定参数类型, 之前可以这么写:

function func(obj: {label: string}) {
    console.log(obj.label)
}

let obj = {size: 10, label: 'object'}
func(obj)

而使用接口, 代码可修改如下:

interface Obj {
    label: string
}
function func(obj: Obj) {
    console.log(obj.label)
}

let obj = {size: 10, label: 'object'}
func(obj)

可选属性"?"

interface SquareConfig {
    color? :string;
    width?: number;
}

function createSquare(config: SquareConfig): {color: string; area: number} {
    let newSquare = {color: 'white', area: 100}
    if (config.color) {
        newSquare.color = config.color
    }
    if (config.width) {
        newSquare.area = config.width * config.width
    }
    return newSquare
}

let mySquare = createSquare({color: 'black'})
console.log(mySquare)

这里"color?"表明color属性为可选, 而{color: string; area: number}表明函数返回值的类型.

只读属性readonly

interface Point {
    readonly x: number,
    readonly y: number,
}

let p1: Point = {x: 10, y: 20}
// error
p1.x = 5

使用ReadonlyArray<T>为只读数组:

let a: number[] = [1, 2, 3, 4]
let ro: ReadonlyArray<number> = a
// error
ro[0] = 12
// error
a = ro

可使用as将只读数组赋值给一般数组:

a = ro as number[]

属性检查

针对上例函数中, 我们调用:

let mySquare = createSquare({colour: 'red', width: 100})

这里TS会直接报错, 因为它认定需要传入的参数为color/width, 没有colour属性.

假定我们程序里要求允许有其它的属性, 则需要修改interface:

interface SquareConfig {
    color?: string,
    width?: number,
    [propName: string]: any,
}

函数类型

我们可定义函数的参数和返回值:

interface SearchFunc {
    (source: string, subString: string): boolean,
}

let mySearch: SearchFunc
mySearch = function(src: string, sub: string): boolean {
    let result = src.search(sub)
    return result > -1
}

let search: SearchFunc
search = function(src, sub) {
    let result = src.search(sub)
    return result > -1
}

这一般适用于大量参数相同的函数的设定.

索引类型

数组的索引, 默认为整数, 但实际上会被转换为字符串. 我们可设定索引类型, 并可设定为只读:

interface StringArray {
    readonly [index: number]: string
}

let myArray: StringArray
myArray = ['Alice', 'Bob']

let myStr: string = myArray[0]
console.log(myStr)
// error
// myStr[2] = 'Mallory'

class类型

我们可以为class定义一个接口:

interface ClockInterface {
    currentTime: Date;
}

class Clock implements ClockInterface {
    currentTime: Date;
    constructor(h: number, m: number) {}
}

我们甚至可以在接口中声明方法, 在类中定义方法:

interface ClockInterface {
    currentTime: Date;
    setTime(d: Date);
}

class Clock implements ClockInterface {
    currentTime: Date;
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) {}
}

如果我们为构造函数实现check:

interface ClockInterface {
    new (hour: number, minute: number);
}

class Clock implements ClockInterface {
    currentTime: Date;
    constructor(h: number, m: number) {}
}

这将报错! 因为TS的class中, 检查的是具体实例. 而构造函数属于静态方法, 无法被检查.

如果要检查构造函数, 只能将构造函数当做一个方法来对待:

interface ClockConstructor {
    new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
    tick();
}

function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
    return new ctor(hour, minute);
}

class DigitalClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("beep beep");
    }
}

class AnalogClock implements ClockInterface {
    constructor(h: number, m: number) {}
    tick() {
        console.log("tick tick");
    }
}

let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);

接口扩展

interface Shape {
    color: string;
}
interface PenStroke {
    penWidth: number;
}

interface Square extends Shape, PenStroke {
    sideLength: number;
}

let square = <Square>{};
square.color = 'blue';
square.sideLength = 10;
square.penWidth = 5.0;

console.log(square);

混合类型

interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}

function getCounter(): Counter {
    let counter = <Counter>function (start: number) {};
    counter.interval = 123;
    counter.reset = function () {};
    return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

 

Classes

我们定义一个简单的class: 属性greeting, 构造函数和方法greet

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return `Hello, ${this.greeting}`;
    }
}

let greeter = new Greeter("world");
console.log(greeter.greet());

继承

使用extends关键字实现继承操作:

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);
    }
}

let sam = new Snake(`Sammy the Python`);
let tom: Animal = new Horse(`Tommy the Palomino`);

sam.move();
tom.move(34);

public, private和protected

默认情况下, class的属性/构造函数/方法, 均为public.

private的属性/方法, 只能在本class内部调用. 在外部或者继承中, 无法调用private声明的属性和方法.

class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

// error
new Animal('cat').name;

private变量/方法是无法进行比较的, 所以下例中animal = employee会报错:

class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

class Rhino extends Animal {
    constructor() { super("Rhino"); }
}

class Employee {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

let animal = new Animal('Goat');
let rhino = new Rhino();
let employee = new Employee('Bob');

animal = rhino;
// error
animal = employee;

protected不仅允许class内部调用, 还允许继承clas调用:

class Person {
    protected name: string;
    constructor(name: string) { this.name = name; }
}

class Employee extends Person {
    private department: string;

    constructor(name: string, department: string) {
        super(name);
        this.department = department;
    }

    public getElevatorPitch() {
        return `Hello, my name is ${this.name} and I work in ${this.department}.`;
    }
}

let howard = new Employee('Howard', 'Sales');
console.log(howard.getElevatorPitch());
// error
console.log(howard.name);

Readonly

我们可以设定属性为只读, 那除了构造函数中进行初始化以外, 其它任何地方都不可以对其进行修改:

class Octopus {
    readonly name: string;
    readonly numberOfLegs: number = 8;
    constructor(theName: string) {
        this.name = theName;
    }
}

let dad = new Octopus('Man with the 8 strong legs');
// error
dad.name = 'Man with the 3-piece suit';

Static

静态属性与实例无关, 与类有关.

class Grid {
    static origin = {x: 0, y: 0};
    calc(point: {x: number; y: number;}) {
        let xDist = (point.x - Grid.origin.x);
        let yDist = (point.y - Grid.origin.y);
        return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
    }
    constructor(public scale: number) {}
}

let grid1 = new Grid(1.0);
let grid2 = new Grid(5.0);

console.log(grid1.calc({x: 10, y: 10}));
console.log(grid2.calc({x: 10, y: 10}));

Abstract Classes

抽象类不同于接口在于它可实现其方法:

abstract class Animal {
    abstract makeSound(): void;
    move(): void {
        console.log('roaming the earth...');
    }
}

 

函数

一般函数可声明为如下格式:

let myAdd = (x: number, y: number) : number => {
    return x + y;
};

console.log(myAdd(1, 3));

函数中某些参数可选, 或者可指定默认值:

let myAdd = (x: number, y?: number) : number => {
    return x + y;
};

let myAdd1 = (x: number, y = 3) : number => {
    return x + y;
};

剩余参数可使用"..."语法糖:

let func = (x: number, ...rest: any[]) => {
    console.log(rest)
};

func(1, 2, 3, 4);

 

转载于:https://my.oschina.net/voler/blog/1525196

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值