Typescript学习笔记及注意事项

一、基本

1、Tuple 元组

元组类型允许表示一个已知元素数量和类型的数组。越界访问时会使用已定义类型的联合类型。

let tuple: [string, number];
tuple = ['tuple', 100]; // 赋值时需要提供所有元组类型中指定的项。
tuple[2] = 'Jane';  // OK
tuple[3] = 3; // OK

2、enum 枚举

enum类型是对JavaScript标准数据类型的补充

enum Color { Red, Green, Yellow, Blue } // 默认从0开始赋值
let c: Color = Color.Red; // 0

也可手动赋值

enum Color1 { Red = 1, Green, Yellow, Blue } // 从1开始
enum Color2 { Red = 1, Green = 6, Yellow = 3, Blue = 2 } // 或全部自定义赋值
enum Color3 { Red = 1, Green = 1.5, Yellow, Blue } // 赋值小数
console.log(Color3.Yellow); // 2.5
console.log(Color3[2.5]); // 'Yellow'

注:未手动赋值的枚举项会接着上一个枚举项递增1。因此可能出现值覆盖情况,应避免值覆盖情况出现。

3、undefined & null

默认情况下null和undefined是所有类型的子类型。当指定了strictNullChecks标记,null和undefined只能赋值给void和它们各自。

4、类型推断

如果没有明确指定类型,typescript会依照类型推论的规则推断出一个类型。

let name = 'Jane';
name = 7; // error

等价于

let name: string = 'Jane';
name = 7; // error

如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成any类型。

let name;
name = 'Jane'; // ok
name = 999; // ok
name = true; // ok

5、联合类型

表示取值可以为多种类型中的一种,使用 | 分隔每个类型。

使用联合属性时,当ts无法推断一个联合类型的变量的确切类型时,我们只能访问此联合类型的所有类型里共有的属性或方法。

function getLength(something: string | number): number {
    return something.length; // error, number不具有length属性
}
 
function getString(something: string | number): string {
    return something.toString(); // ok
}

6、数组

(1)数组类型表示方法

  • 类型 + 方括号 → String[]
  • 数组泛型 Array → Array
  • 接口表示法(不常用)
    interface StringArray {
    [index: number]: string;
    }

(2)arguments类数组描述

function add() {
    let args: {
        [index: number]: any;
        length: number;
        callee: Function;
    } = arguments;
}

上例等价于(实际上,常用的类数组都有子集的接口定义,如IArguments, NodeList, HTMLCollection等):

function add() {
    let args: IArguments = arguments;
}
 
/**
 * interface IArguments {
 *      [index: number]: any;
 *      length: number;
 *      callee: Function;
 * }
 */

7、函数

一个函数有输入和输出,因此在定义类型时,对输入和输出都需要考虑。
(1)函数声明

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

(2)函数表达式

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

在TypeScript中, => 用来表示函数的定义。上述等价于:

interface SumFunc {
    (x: number, y: number) => number
}
let mySum: SumFunc;
mySum = function (x: number, y: number): number {
    return x + y;
};

注意:函数参数中的可选参数(y?: number)必须接在必需参数后面。即可选参数后面不可再出现必需参数。

(3)参数默认值
在 ES6 中,我们允许给函数的参数添加默认值,TypeScript 会将添加了默认值的参数识别为可选参数,此时就不受「可选参数必须接在必需参数后面」的限制了。

即可发现,可确定有值的属性应放在无法确认是否有值的参数前面。

function sum(x: number = 1, y: number): number {
    return x + y;
}

(4)剩余参数rest

function push(array: any[], ...items: any[]) {
    items.forEach(function(item) {
        array.push(item);
    });
}
 
let a = [];
push(a, 1, 2, 3);

(5)函数重载

// 函数定义
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('');
    }
}

TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。

8、类型断言 value as type && value (在jsx中只可使用as类型)

类型断言常见使用场景:(类型断言表示开发者明确知道当前属性的类型,ts编译器不会对其进行校验。因此,如果断言不当,在运行时可能会导致报错。)
(1)当使用了联合类型时,在还不确定类型时就访问其中一个,这时可将当前类型断言为联合类型中的一个

interface Cat {
    name: string;
    run(): void;
}
interface Fish {
    name: string;
    swim(): void;
}
​
function isFish(animal: Cat | Fish) {
    if (typeof (animal as Fish).swim === 'function') {
        return true;
    }
    return false;
}

(2)将父类断言为更加具体的子类

interface ApiError extends Error {
    code: number;
}
interface HttpError extends Error {
    statusCode: number;
}
​
function isApiError(error: Error) {
    // 父类Error中不存在code属性,如果直接使用会报错
    if (typeof (error as ApiError).code === 'number') {
        return true;
    }
    return false;
}

(3)将类型断言为any

window.foo = 1;

上面的例子中,我们需要将 window 上添加一个属性 foo,但 TypeScript 编译时会报错,提示我们 window 上不存在 foo 属性。 此时我们可以使用 as any 临时将 window 断言为 any 类型

(window as any).foo = 1;

(4)将any断言为其他具体类型

let pig: any = 'zhu';
let p = (pig as string); // 'zhu',此时P被断言为string类型
p = 1; // error
p = 'pig'; // ok

二、类和接口

相关概念:
类: 定义了一件事物的抽象特点,包含它的属性和方法。
抽象类:抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现。
接口:不同类之间公有的属性或方法,可以抽象成一个接口。
接口可以被类实现。一个类只能继承自另一个类,但是可以实现多个接口。

1、只读属性

有一些属性只能在对象刚刚创建的时候修改其值。可用readonly来指定只读属性,指定后一旦赋值,就不能再改变了。

interface Point {
    readonly x: number;
    readonly y: number;
}
 
let p1: Point = { x: 1, y: 2 };
p1.x = 3; // error!

const vs readonly
最简单判断该用readonly还是const的方法是看要把它做为变量使用还是做为一个属性。
做为变量使用的话用 const,若做为属性则使用readonly。

2、任意属性

interface SquareConfig {
    color?: string;
    width?: number;
    [propName: string]: any; // 表示带有任意数量的其他属性
}
 
const sq: SquareConfig = {
    color: 'red',
    height: 18,
}

注意:一旦定义了任意属性,那么确定属性和可选属性的类型都必须是该类型的子集。

3、类实现接口

一个类可以实现多个接口

interface Alarm {
    alert(): void;
}
 
interface Light {
    lightOn(): void;
    lightOff(): void;
}
 
class Car implements Alarm, Light {
    alert() {
        console.log('Car Alarm');
    }
    lightOn() {
        console.log('Car light on');
    }
    lightOff() {
        console.log('Car light off');
    }
}

三、其他

1、interface vs type

相同点:
(1)都可以用于描述对象/函数(注意写法差别)
interface:

 interface Person {
  name: string;
  age: number;
 }
 
 interface CreatePerson {
   (name: string, age: number): void;
 }

type:

type Person = {
  name: string;
  age: number;
}
 
type CreatePerson = (name: string, age: number) => string;

(2)都可用于类型继承
interface继承:
①interface extends interface:

interface Name {
   name: string;
}
 
interface Person extends Name {
  age: number
}
②interface extends type:
type Name = {
  name: string;
}
 
interface Person extends Name {
  age: number
}

type继承:
① type extends type

type Name = {
 name: string
}
 
type Person = Name & { age: number };
② type extends interface
interface Name = {
  name: string
}
 
type Person = Name & { age: number }

不同点:
(1) interface可以而type不行(不完全举例)

interface Person {
    name: string;
    age: number;
}
 
interface Person {
    weight: number;
}
 
/**
* 上述Person接口会进行声明合并
* interface Person {
*      name: string;
*      age: number;
*      weight: number;
* }
 */

(2) type可以而interface不可以(不完全举例)

可定义基础类型别名:

type newString = string;
const name: newString = 999; // error
const name1: newString = 'Jane'; // ok

联合类型:

type stringOrNumber = string | number;
type Text = string | { text: string }

定义字符串字面量类型:

type EventNames = 'click' | 'mousemove' | 'scroll';
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值