2

最近开始在项目中真正使用 typescript 了,为了弥补知识点上的不足,我阅读了「深入理解 typescript」,下面是我记录的笔记,在此跟大家分享我觉得对于新手比较重要的一些点。

变量声明和类型声明

TS 的变量声明是声明一个变量,比如 const/let/class,其中 class 同时也可用于类型声明。

使用类实现接口

使用 implements 关键字可以让接口限制类内部的类型:

interface Point {
    x: number;
    y: number;
    z: number; // New member
}
class MyPoint implements Point { // ERROR : missing member `z`
    x: number;
    y: number;
}

使用箭头函数做类型注解

可以使用箭头函数做类型注解,所以可能会出现有两个箭头的函数,第一个箭头是类型注解,第二个箭头是函数体本身。

// 普通函数
const simple = function(foo: number): string {return foo.toString()};
// 箭头函数
const simple: (foo: number) => string = (foo) => foo.toString();

类型断言 as

类型断言 as 允许我们覆盖原有的类型推导。

function handler (event: Event) {
    let mouseEvent = event as MouseEvent;
}

对象的属性

Freshness 是针对对象字面量的更为严格的检查,它使用对象字面量作为类型注解,提供了两个功能:

  1. 可选属性
var x: { foo: number };
x = { foo: 1, baz: 2 };  // Error, excess property `baz`

var y: { foo: number, bar?: number };
y = { foo: 1, baz: 2 };  // Error, excess or misspelled property `baz`
  1. 允许额外属性
var x: { foo: number, [x: string]: any };

x = {foo: 1, bar: 2}; // it works

泛型到底是什么?

泛型的作用是在内部成员之间提供一些约束,可以作用的成员是:

  • 类的实例
  • 类的方法
  • 函数的参数
  • 函数的返回值
class Queue<T> {
  private data = [];
  push(item: T) { this.data.push(item); }
  pop(): T | undefined { return this.data.shift(); }
}

// 在这里使用泛型,可以使得这个 queue 实例只接受 number 类型的元素
const queue = new Queue<number>();
queue.push(0);
queue.push("1"); 
function reverse<T>(items: T[]): T[] {
    var toreturn = [];
    for (let i = items.length - 1; i >= 0; i--) {
        toreturn.push(items[i]);
    }
    return toreturn;
}

var sample = [1, '2', 3];
//在调用函数的时候,typescript 会根据传入的参数类型自动确定T的类型,在这里是 number|string
var reversed = reverse(sample);
console.log(reversed); // 3,2,1”

如果你的泛型只在一个地方使用到,那么相当于没有进行约束,这个时候并不安全,比如:

declare function parse<T>(name: string): T;
//相当于
declare function parse(name: string): any;

当我们把 API 层抽象出来时,可以使用嵌套的泛型来帮助我们进行类型推导:

  1. 设置一个通用的数据返回的 interface:ResponseData
export interface ResponseData<T = any> {
  // 状态码
    code: number;
  // 传入T确定返回数据的类型
  result: T;
  // 消息
  message: string;
}
  1. 在 API 使用层对具体的返回数据类型进行类型注解:getUserResp
  2. 调用函数时传入 getUserResp 到 ResponseData
import api from './axios';

interface getUserResp {
  name: string;
  age: number;
}

export function getUser() {
    return api.get<ResponseData<getUserResp>>('/api/v1/user').then(res => console.log(res.data))
}

Never 是什么?

Never 是 ts 的一种底层类型,乍一看跟 void 很像,但是它更多的用来表示在函数 never return something,比如有死循环、或者throw error 了。而且,never 类型仅能被赋值给另一个 never 类型。

function fail(msg: string): never {
    throw new Error(msg)
}

索引签名

索引签名是 typescript 对于对象的索引(和值)即进行约束的一个方式,它约束对象的索引必须是 number 或者 string。

interface foo {
  // 约束所有 key 必须是 string,
  [x: string]: number;
  x: number;
  y: number
}

type Index = 'a' | 'b' | 'c';
interface foo1 {
  [x in Index]?: string;
}
// foo1 是
// type FromIndex = {
//   a?: number;
//   b?: number;
//   c?: number;
// }

Typeof

Typescript 里的 typeof 跟 JavaScript 里的有一些不同,对于一个类或者对象,它的结果是输出它的属性。对于字符串和数字,则会因为使用 let 或者 const 而得到不同的结果。

const foo2 = 'Hello World'
// let foo2 = 'Hello World' 就可以使得 bar 的类型是 string

// bar 的类型是 'Hello World'
let bar: typeof foo2;

// bar can only ever be assigned to `Hello World`
bar = "Hello World"; // Okay!
bar = "anything else "; // Error!”

typeof 还可以与 keyof 搭配用于获取对象的键

const colors = {
  red: 'reddish',
  blue: 'bluish'
}
type Colors = keyof typeof colors;

let color: Colors; // same as let color: "red" | "blue"
color = 'red'; // okay
color = 'blue'; // okay
color = 'anythingElse'; // Error: Type '"anythingElse"' is not assignable to type '"red" | "blue"”

竹之同学
506 声望183 粉丝

人在囧途