深入浅出TypeScript

671 阅读6分钟

一、基础类型

string、number、boolean

let str: string = "hello"
let num: number = -9  // 可以是负数,十六进制,十进制,八进制,二进制
let bol: boolean = false

str = 90 // ts会报错:不能使用其他类型

// 使用模板字符串
let sentence: string = `${str} world`

数组

// 使用数组泛型 Array<元素类型>
let list: Array<number> = [1, 2, 3]

// 元素类型接[]
let list1: number[] = [1, 2, 3]

元组 Tuple

允许一个已知元素数量和类型的数组,各元素的类型不必相同

let x: [string, number]
x = ["hello", 10] // 元素类型需要对应

console.log(x[0].substr(1)) // OK
console.log(x[1].substr(1)) // Error, number没有substr方法

// 不能越界访问
console.log(x[4]) // error

联合类型:允许多个元素类型

let Day: string | number
Day = "一日" // ok
Day = 1 // ok

Day = false // error

枚举

enum Color {Red, Green, Blue}
let c: Color = Color.Green;

console.log(c) // 1,默认编号从0开始

// 设置枚举值
enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];

console.log(colorName); // 显示 "Green"

自动类型推断、any

  1. 自动类型推断
let notSuer = 4
notSuer = "hello" // 报错
  1. any:允许任何数据类型
let notSuer: any = 4
notSuer = "hello" // ok
notSuer = false // ok

notSuer.abc(); // ok,any类型不做类型检查

void

无返回值。它没有任何类型,刚好与any相反

function warnUser(): void {
    console.log("This is my warning message"); // ok
}

function echo(): void {
    return 9 // error
}

// 声明一个void类型的变量没有意义,因为只能为它赋予undefined和null
let unusable: void = undefined;

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 throwError(mag: string):never {
    throw new Error(mag);
}

function len(x: string | undefined | null) {
    if (!x) throwError("undefind argument");
    x.length;
}

let x = null;
len(x);

null 和undefined

默认情况下nullundefined是所有类型的子类型。 就是说你可以把 nullundefined赋值给任何类型的变量

指定了--strictNullChecks标记,nullundefined只能赋值给void和它们各自。

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

二、函数

给每个参数添加类型,再为函数本身添加返回值类型

function add(x: number, y: number): number {
    return x + y;
}

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

完整函数类型

let myAdd: (x: number, y: number) => number =
    function(x: number, y: number): number { return x + y; };
    
let myAdd: (baseValue: number, increment: number) => number =
    function(x: number, y: number): number { return x + y; };
**// 两种写法一样
// 函数类型包含两部分:参数类型和返回值类型,为每个参数指定一个名字和类型。名字只是为了增加可读性。
// 只要参数类型匹配,那么它就是有效的函数类型,而不在乎参数名是否正确**
**// => 表示返回值类型,不要和es6的箭头函数混淆**

可选参数

function buildName(firstName: string = "", lastName?: string) {
    return firstName + " " + lastName;
}

let result1 = buildName("Bob");                  // ok, 第二个选填
let result2 = buildName("Bob", "Adams", "Sr.");  // error, 超过两个参数
let result3 = buildName(undefined, "Adams");     // ok, 第一个不填要设置默认参数,并且传undefined

剩余参数:除了必填参数外,接受不确定的剩余参数

function buildName(firstName: string, ...restOfName: string[]) {
    return firstName + " " + restOfName.join(" ");
}

buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

重载

// 前两次是函数定义,最后一个是函数实现
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

三、interface 接口

描述一个函数的结构

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

let mySearch: searchFunc = function(source: string, subString: string) :boolean {
    return source.search(subString) !== -1
}

描述一个对象的结构

interface Person{
    name: string
    age: number
}

let tom: Person = {
    name: "tom",
    age: 25,
    from: "" // error, 不能多写
}

let bob: Person = {
    name: "bob", // error, 也不能少写
}

let bob: Person = {
    name: "bob",
    age: "25", // error, 类型不对
}

可选属性

interface Person{
    name?: string
    age: number
}

let bob: Person = {
    age: 25, // ok, name选填
}

索引签名:可以定义额外的属性

interface Person{
    name: string
    age: number
    [propName: string]: any
}

let bob: Person = {
    name: "bob",
    age: 25, 
    from: "china",
    sex: "man"
}

四、类

定义类

class Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    sayName() {
        return this.name
    }
}

let animal = new Animal("bob")
console.log(animal.name) // bob
console.log(animal.sayName()) // bob

使用public修饰可省略定义成员

class Animal {
    constructor(public name: string) {
      this.name = name;
    }
    sayName() {
      return this.name;
    }
}

let animal = new Animal("bob");
console.log(animal.name); // bob

继承

class Animal {
    constructor(public name: string) {
        this.name = name;
    }
    sayName() {
        return this.name;
    }
}

class Cat extends Animal {
    constructor(public name: string) {
        super(name) // 调用父类的构造函数
    }
    sayHi(){
        conso.log(this.name)
    }
}
let cat = new Cat("bob");
console.log(cat.name); // bob
cat.sayName() // ok, 调用父类的方法
cat.sayHi() // ok, 调用自己的方法

get和set

class Animal {
    constructor(public name: string) {
        this.name = name;
    }
    get surnName() {
        return this.name;
    }
    set surnName(val: string){
        this.name = val;
    }
}

let animal = new Animal("bob");
animal.surnName = "tom"
conso.log(animal.surnName) // tom

static

class Animal {
    constructor(public name: string) {
        this.name = name;
    }
    static isAnimal(a: string){
        return a instanceof Animal
    }
}

let a = new Animal("bob")
console.log(Animal.isAnimal(a)) // true, 是类的实例

public:默认就是public,制定成员是可见的

class Animal {
    public name: string;
    constructor(name: string) {
        this.name = name;
    }
    public sayName() {
        return this.name
    }
}

let animal = new Animal("bob")
animal.name // ok

private:私有的,在当前类的外部不能访问

class Animal {
    private name: string;
    constructor(name: string) {
        this.name = name; // 内部可以访问私有变量或方法
    }
    private sayName() {
        return this.name
    }
    sayHi(){
      return this.sayName() // 内部可以访问私有变量或方法
    }
}

let animal = new Animal("bob")
animal.name // error, 私有的
animal.sayName() // error, 私有的
animal.sayHi() // ok

// 继承
class Cat extends Animal {
    sayHi(){
        this.sayName() // error, 子类不能访问父类的私有变量或方法
    }
}

protected:受保护的,当前类内部和子类内部可以访问,不能在实例上访问

class Animal {
    protected name: string;
    constructor(name: string) {
        this.name = name; // 内部可以访问私有变量或方法
    }
    protected sayName() {
        return this.name
    }
}

let animal = new Animal("bob")
animal.name // error, 不能在实例上访问
animal.sayName() // error, 不能在实例上反问

// 继承
class Cat extends Animal {
    sayHi(){
        this.sayName() // ok, 子类可以访问
    }
}

let cat = new Cat()
cat.name // error, 子类实例上也不能访问
cat.sayName() // error, 子类实例上也不能访问

abstract:类中的抽象方法必须在子类中实现,

abstract class Animal {
    constructor(public name: string) {
    }
    abstract render():void  // 必须在子类中实现
    sayHi(){  // 可不在子类中实现
    } 
}

class Cat extends Animal {
    constructor() {
        super('调用super'); // 子类的构造函数中必须调用 super()
    }
    render(){
        console.log("实现")
    }
}

readonly:只读的,只读属性必须在声明时或构造函数里被初始化

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

let animal = new Animal("bob") 
dad.name = "tom" **// error, name是只读的不能修改**

构造函数

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

let animal: Animal = new Animal("bob") /**/ 意思Animal的实例类型,是Animal**

五、泛型

  • 不用泛型的列子
function fn(arg: number): number {
    return arg;
}

// 或则使用any定义函数
function fn(arg: any): any {
    return arg;
}
  • 定义泛型
// T传入的类型是(比如:number),那么T就是number类型
function fn<T>(arg: T): T {
    return arg;
}

fn<string>("myString") // 明确指定T是string

fn("myString"); // 不指定,则自动类型推断
  • 泛型类
class ClaaNum<T> {
   zeroValue: T;
   add: (x: T, y: T) => T;
}

let claaNum = new ClaaNum<number>();
claaNum.zeroValue = 0;
claaNum.add = function (x, y) {
    return x + y;
};