最近开始在项目中真正使用 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 是针对对象字面量的更为严格的检查,它使用对象字面量作为类型注解,提供了两个功能:
- 可选属性
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`
- 允许额外属性
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 层抽象出来时,可以使用嵌套的泛型来帮助我们进行类型推导:
- 设置一个通用的数据返回的 interface:ResponseData
export interface ResponseData<T = any> {
// 状态码
code: number;
// 传入T确定返回数据的类型
result: T;
// 消息
message: string;
}
- 在 API 使用层对具体的返回数据类型进行类型注解:getUserResp
- 调用函数时传入 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"”
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。