TypeScript 快速入门
这是一份 TypeScript 快速入门小文档,如果你是 TypeScript 新手你可以从这里学到 TypeScript 入门知识,如果你是 TypeScript 体操员欢迎进行补充。
什么是 TypeScript
TypeScript 是 JavaScript 类型的超集,它可以编译成纯 JavaScript。TypeScript 可以编译出纯净、 简洁的 JavaScript 代码,并且可以运行在任何浏览器上、Node.js环境中和任何支持 ECMAScript 3(或更高版本)的 JavaScript 引擎中。
TypeScript 拥有强大的类型推断,通过类型推断你可以洞察当前代码的行为以及获取代码提示。
TypeScript 提供最新的和不断发展的 JavaScript 特性,但是在编译时会提供对应版本的 JavaScript 代码。
类型声明
进行类型声明后,使得类型被标注,编译器会在编译过程中根据标注的类型进行检测,使数据的使用更安全,帮助我们减少错误。如果不写明类型,TypeScript 会进行类型推断。
类型说明
// 基本数据类型
let isDone: boolean = false;
let decLiteral: number = 6;
let name: string = "bob";
let data:undefined = undefined;
let info:null = null;
// 对象类型
let ot: {x: number, y: string} = {
x: 1,
y: 'zmouse'
};
// 数组类型
let arr1: string[] = [];
let arr2: Array<number> = [];
// 元祖(元组类似数组,但是存储的元素类型不必相同)
let data1: [string, number] = ['test', 100];
// 枚举
enum HTTP_CODE {
OK = 200,
NOT_FOUND = 404
};
// 无值类型
function fn():void {
// 没有 return
}
// Never类型
function fn(): never {
throw new Error('error');
}
// 任意类型(不建议使用)
let anyData:any = 'any'
// 未知类型
let unknowData:unknown = 'unknow'
// 函数类型
function maxA(x:number,y:number):number {
return x > y ? x : y;
}
类型声明通用规则
- 类型声明一般都会首字母大写,例如:
Data。 - 注意
undefined、null的语义:undefined为此处应该有值但未定义,null为此处不应该有值。 - 在很多
Lint规则中关于对象标注类型不能直接声明一个对象为Object,而是手动声明这个对象的字段或者定义一个新的对象类型(这个很好理解,因为Object相当于也是逃离了类型约束)。 - 枚举中一般 key 都是全大写加下划线,例如:
NOT_FOUND。 any在一般情况我们一定要禁止使用,采用unknown类型来替代any,并在后面进行断言给予正确的类型。- 在很多
Lint规则中关于对象标注类型不能直接声明一个函数为Function,而是手动声明这个函数的参数和返回(如果你实在不知道,也可以使用Function加忽略此行)。
关于类型声明的特殊技巧
断言
有时候我们需要得到具体的类型,而且统一的类型,例如,1 我们想要得到 1 类型,而非 number 类型,这时候我们就可以使用断言。
const a = 1 as const;
断言加 unknown 替代 any 类型
因为 any 类型是相关让
TypeScript对这个变量进行不检测了,这其实是非常危险了。更多的时候我们只是暂时跳过这个时候的检测,放在后面处理。
function getData(val:unknown){
// ...
// 这里我们已经知道这里是字符串类型
const temp = val as string
temp.toFixed(2)
// ...
}
根据常量获取类型
很多时候我们想通过常量得到类型,这样修改常量我们也会得到正确的诶性。
// 枚举
enum HTTP_CODE {
OK = 200,
NOT_FOUND = 404,
}
type CodeKey = keyof typeof HTTP_CODE
// 这里类型会被转换为字符串而不是数字(需要注意)
type Code = `${HTTP_CODE}`
// 普通定义(更推荐)
const HTTP_CODE_T = {
OK: 200,
NOT_FOUND: 404,
} as const
type CodeKeyT = keyof typeof HTTP_CODE_T
type CodeT = typeof HTTP_CODE_T[CodeKeyT]
定义类型
对复杂的对象类型进行标注的一种方式,或者给其它代码定义一种契约(比如:类)。
// 更推荐使用 interface 定义类型,因为错误信息会更准确
interface Point {
// 必选
x: number;
// 可选
y?: string;
// 只读
readonly a: number;
}
// 值得注意的是,在你使用 `Record` 高级对象的时候,只能使用 type 定义类型传递
type Point2 = {
z: string;
// 任意类型
[prop: string]: number;
}
类型深入
一些特殊的类型
// 联合类型
type Info = number | string
// 交叉类型
type Data = { a: number; b: string } & { a: number; c: string }
// 字面量类型
type Direction = 'left' | 'top' | 'right' | 'bottom'
类型操作符
typeof
和 javaScript 表现一致,并且同时可以判断出类型。
let colors = {
color1: 'red',
color2: 'blud'
};
type tColors = typeof colors;
// 或者你可以在 if 里判断
function add(num:number|string){
if(typeof num === 'number'){
return 50 + num
}else{
// 这里我们可以正常调用字符串的方法
return 50 + num.toFixed(2)
}
}
keyof
获取类型的所对应的类型的key的集合,返回值是key 的联合类型(注:keyof 操作的是类型)。
interface Person {
name: string;
age: number;
};
type personKeys = keyof Person;
// 等同:type personKeys = "name" | "age"
in
in 操作符对值和类型都可以使用。针对值进行操作,用来判断值中是否包含指定的 key。
interface Person {
name: string;
age: number;
}
type personKeys = keyof Person;
type newPerson = {
[k in personKeys]: number;
/**
等同 [k in 'name'|'age']: number;
也可以写成
[k in keyof Person]: number;
*/
}
/**
type newPerson = {
name: number;
age: number;
}
*/
extends
用于继承类型
interface type1 {
x: number;
y: number;
}
interface type2 extends type1 {}
type type1 = {
x: number;
y: number;
}
function fn<T extends type1>(args: T) {}
// 在这里也可以传入泛型
fn({x:1, y: 2});
函数重载
有时候我们需要根据传入函数不同的参数或者类型来达到返回的类型因此而不同,这个时候我们就需要用到重载。
function add(val: number): number;
function add(val: string): string;
function add(val: number | string): number | string {
if (typeof val === 'number') {
return 1
} else {
return '1'
}
}
预置条件类型
TS提供了几种内置的预定义的条件类型,可以让我们更快的操作类型
- Exclude<T, U> - 用于从类型T中去除不在U类型中的成员
- Extract<T, U> - 用于从类型T中取出可分配给U类型的成员
- NonNullable<T> - 用于从类型T中去除undefined和null类型
- ReturnType<T> - 获取函数类型的返回类型
- InstanceType<T> - 获取构造函数的实例类型
Exclude<T, U>
用于从类型T中取出不在U类型中的成员
type temp = Exclude<"a"|"b"|"c","b"|"c"|"d">
// "a"
Extract<T, U>
用于从类型T中取出可分配给U类型的成员
type temp = Extract<"a"|"b"|"c","b"|"c"|"d">
// "b" | "c"
NonNullable<T>
用于从类型T中去除undefined和null类型
type temp = Extract<string | number | undefined>
// string | number
ReturnType<T>
获取函数类型的返回类型
type temp = ReturnType<(s:string)=>string>
// string
InstanceType<T>
获取构造函数的实例类型
class C {
x = 0
y = 0
}
type temp = InstanceType<typeof C>
// C
高级类型
预置的高级类型(高级类型也是由基础类型设置过来的)
以下所有例子皆以 person 为例
interface Person {
name: string;
age?: number;
}
Partial
将对象中所有的属性变为可选参数
源码:
type Partial<T> = {
[P in keyof T]?: T[P];
};
实例:
type person2 = Partial<Person>;
// person2 === {name?: string; age?: number}
Required
将对象中所有的属性变为必选参数
源码:
type Required<T> = {
[P in keyof T]-?: T[P];
};
实例:
type person3 = Required<Person>;
// person3 === {name: string; age: number}
Readonly
将对象中所有的属性变为只读参数
源码:
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
实例:
type person4 = Readonly<Person>;
// person4 === {
// readonly name: string;
// readonly age?: number;
// }
Pick
从类型中筛选出类型
源码:
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
实例:
type person5 = Pick<Person, "name">;
// person5 === {name: string}
Record
根据 key 以及传入的类型得出类型
源码:
type Record<K extends keyof any, T> = {
[P in K]: T;
};
实例:
type person6 = Record<'name' | 'age', string>
// person6 === {name: string; age: string}
Omit
以一个类型为基础支持剔除某些属性,然后返回一个新类型。
源码:
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
实例:
type PersonWithoutLocation = Omit<Person, 'age'>;
// person6 === {name: string;}
其他
编译选项
如果一个目录下存在一个tsconfig.json文件,那么它意味着这个目录是TypeScript项目的根目录。 tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项。
详情见:编译选项