基本类型
示例代码:typescript-demos
为什么要用 TypeScript?
好处:
- 规避大量低级错误,避免时间浪费(省时)
- 减少多人协作项目的成本,大型项目友好(省心)
- 良好代码提示,不用反复文件跳转或者翻文档(省力)
坏处:
- 与其它框架结合会有坑
- 配置学习成本高
- 要学习额外的类型系统
TypeScript 开发环境设置
# 全局安装(可以使用 `tsc` 命令)
npm install -g typescirpt
# 初始化目录
npm init
# 初始化ts环境(会多一个 `tsconfig.json` 文件,即项目的ts配置文件)
tsc --init
关于
tsconfig.json
更多说明,可以参考自动生成的tsconfig.json
注释或官网文档1。
在 package.json
加上两个 script:
build
编译build:w
监听并编译
"scripts": {
"build": "tsc",
"build:w": "tsc -w"
}
基础类型
原始类型
其它常见类型
boolean 布尔值
const isSpinning: boolean = false;
number 数字
const size: number = 6;
注:除了十进制,还可以是十六进制、二进制、八进制字面量。
string 字符串
const customer: string = 'Tonny';
注:除了单双引字符串,还可以是模板字符串(被反引号包围)。
void 空值
void
表示没有任何类型- 当一个函数没有返回值时,它的返回类型就是
void
- 声明一个
void
类型的变量没什么用,因为它只能被赋予undefined
和null
function sayHi(): void {
alert('Hi');
}
null & undefined
- 默认情况下,
null
和undefined
是所有类型的子类型,即可以把它们赋值给以上类型 undefined
能赋值给void
- 只有
--strictNullChecks
设置为false
时null
才能赋值给void
let u: undefined = undefined;
let n: null = null;
let v1: void = undefined; // OK
// let v2: void = null; // 注意:strictNullChecks=false时才可以这样赋值
tsconfig.json
开启 strictNullChecks
检查:
{
"compileOnSave": false,
"compilerOptions": {
"strictNullChecks": true,
"skipLibCheck": true,
}
}
symbol 唯一标识
使用 Symbol
时,必须添加 es6
的编译辅助库:
{
"lib": ["ES6", "DOM"],
}
该类型通过 Symbol
构造函数创建:
const s1 = Symbol('s1');
const s2 = Symbol('s2');
Symbol 的值时唯一不变的:
Symbol('s1') = Symbol('s1'); // false
BigInt 大数整数
使用 BigInt
必须添加 ESNext
编译辅助库:
"lib": ["es6", "dom", "ESNext"],
Any 任何值
- 可以为还不清楚类型的变量指定该类型
any
- 多人协作协作项目大忌,很可能把
TypeScript
变成AnyScript
,所以非不得情况不建议使用
let a: any;
unknown 未知值
- ts 3.0 引入的新类型,
any
类型对应的安全类型 - 与
any
对比,unknown
会更严格:当unknown
类型被确定是某个类型之前,它不能被进行任何操作,如实例化、getter、函数执行等 - 缩小其类型范围可以执行
unknown
,如用 instanceof 判断是否日期、数组等具体类型
let a: any;
a[0] = 1; // OK
let un: unknown;
// un[0] = 1; // Error:未确定类型之前不能进行操作
if (un instanceof Array) { // 缩小范围类型,让unknow可以执行操作
un[0] = 1; // OK
}
never 永不存在
never
表示那些永不存在的值的类型- 它是任何类型的子类型,即可以赋值给任何类型
- 没有类型是
never
的子类型,即没有任何类型(包括any
)可以赋值给never
(除了never
本身) - 常见的
never
类型有:总是会抛出异常或根本就不会有返回值的函数表达式;箭头函数表达式的返回值类型;被永不会为真的类型保护所约束的变量
// 返回never的函数必须存在无法到达的终点
function error(message: string): never {
throw new Error(message);
}
Array 数组
两种方式可以定义数组:
// 使用数组泛型,`Array<元素类型>`
let list: Array<number> = [1, 2, 3];
// 使用 `元素类型[]`(这种更常用)
let list: number[] = [1, 2, 3];
Tuple 元组
- 与数组类型很相似,表示一个已知元素数量和类型的数组
- 元组中元素的类型可以不同
let t: [string, number]
t = ['hi', 10]; // OK
t = [10, 'hi']; // Error: 元素类型顺序有误
t = ['hi', 10, 10]; // Error: 数组长度
Object 对象
Object
表示非原始类型,也就是除了number
,string
,boolean
,symbol
,bigint
,null
或undefined
之外的类型- 普通对象、枚举、数组、元组都是
object
类型
类型断言与类型守卫
类型断言
- 假定你比 TS 更了解某个值的详细信息,这时就可以通过类型断言的方式告诉编译器
- 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构
- 类型断言有两种形式:“尖括号”语法和
as
语法
“尖括号”语法
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
as
语法
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
一个是使用场景:
// 情况1
// const person = {};
// person.name = 'tommoy'; // Error: 属性不存在
// person.age = 20; // Error: 属性不存在
// 情况2
interface Person {
name: string,
age: number
}
const person = {} as Person;
person.name = 'tommy'; // OK
person.age = 18; // OK
类型守卫
- 类型守卫,即缩小类型的范围
- 常见使用方式有:
instanceof
、in
、字面量类型守卫
instanceof
类型保护是通过构造函数来细化类型的一种方式:
class Cat {
name = 'cici';
color = 'white';
}
class Dog {
name = 'bubu';
weight = 90;
}
function getSometing(arg: Cat | Dog) {
// 类型细化为 `Cat`
if (arg instanceof Cat) {
console.log(arg.color); // OK
// console.log(arg.weight); // Error:类型“Cat”上不存在属性“weight”
}
// 类型细化为 `Dog`
if (arg instanceof Dog) {
// console.log(arg.color); // Error:类型“Dog”上不存在属性“color”
console.log(arg.weight); // OK
}
}
in
与 instanceof
类似,x in y
表示 x 属性在 y 中存在:
class Cat {
name = 'cici';
color = 'white';
}
class Dog {
name = 'bubu';
weight = 90;
}
function getSometing(arg: Cat | Dog) {
if ('color' in arg) {
console.log(arg.color); // OK
// console.log(arg.weight); // Error:类型“Cat”上不存在属性“weight”
}
if ('weight' in arg) {
// console.log(arg.color); // Error:类型“Dog”上不存在属性“color”
console.log(arg.weight); // OK
}
}
字面量类型守卫:
type Cat = {
name: 'cici';
age: number;
}
type Dog = {
name: 'bubu';
weight: number;
}
function doSomething(arg: Cat | Dog) {
if (arg.name === 'cici') {
console.log(arg.age); // OK
// console.log(arg.weight); // Error: 类型“Cat”上不存在属性“weight”。
} else {
// console.log(arg.age); // Error: 类型“Dog”上不存在属性“age”。
console.log(arg.weight); // OK
}
}