基础
类型推导
let value = 'abcd'
value = 123456
// 等价于以下代码
let value : string = 'abcd'
value = 123456
类型系统
基本类型
let success : boolean = true
let age : number = 20
let name : string = 'akara'
let u : undefined = undefined
let n : null = null
// void 用来代表空值,值只能是undefined或null
let value : void = undefined
value = null
字面量类型
// 字符串字面量类型
let str: 'small' = 'large'
// 数字字面量类型
let num: 1 = 1
// 布尔字面量类型
let boo: true = true
字面量类型可以视为相应类型的子集,如字符串字面量类型可以视为字符串类型的子集。
值得注意的是,用let
和const
声明变量时,其类型是不同的。
let name = 'aka' // string
const name = 'aka' // 'aka'
数组与元祖
JavaScript
中只存在数组的概念,TypeScript
在数组的基本上抽象出元祖的概念,但本质都是一样的。
TypeScript
中数组只可以存储一种数据类型,数组的长度可变;而元祖可以存储不同的数据类型,但元祖的长度不可变。
数组
定义
let a1: Array<number> = [1, 2, 3];
let a2: number[] = [1, 2, 3];
let a3 = [1, 2, 3];
本质
type arr1 = [1, 2, 3];
type arr1 = {
[x: number]: number;
length: number;
// 其他方法
}
// readonly的本质
type arr2 = readonly [1, 2, 3];
type arr2 = {
[x: number]: number;
readonly length: number;
// 其他方法
}
元组
定义
let t1: [number, number] = [1, 2];
let t2 = [1, 2] as const;
通过as const
能够将一个数组断言为readonly
元组
本质
type tuple = [1, 2, 3];
type tuple = {
[x: number]: 1 | 2 | 3;
0: 1;
1: 2;
2: 3;
length: 3;
// 其他方法
}
// readonly的本质
type tuple = readonly [1, 2, 3];
type tuple = {
[x: number]: 1 | 2 | 3;
readonly 0: 1;
readonly 1: 2;
readonly 2: 3;
readonly length: 3;
// 其他方法
}
any[]
所有非readonly
元组都是any[]
的子类型,所有元组都是readonly any[]
的子类型。(any[]
是readonly any[]
的子类型)
因此如果我们的泛型可以同时接收数组和元组,可以使用T extends readonly any[]
进行约束
type B = number[] extends readonly number[] ? true : false; // true
type A = readonly number[] extends number[] ? true : false; // false
// 对比
type A = {
readonly age: number;
}
type B = {
age: number;
}
type Test = A extends B ? true : false; // true
type Test2 = B extends A ? true : false; // true
函数
函数对参数数量和类型有着严格的要求
function A(name?: string): string | undefined { // name的实际类型为string | undefined
return name
}
function A(name = 'akara'): string {
return name
}
函数声明
function sum(x: number, y: number): number { // 函数声明
return x + y;
}
const mySum = function (x: number, y: number): number { // 函数表达式
return x + y;
};
const mySum = (x: number, y: number): number => { // 箭头函数表达式
}
// 重载函数声明
function A(a: string, b: number): number;
function A(a: number, b: string): string;
function A<T extends string | number>(a: T, b: T): T | undefined {
if (a === '1') return b
if (a === 1) return b
return
}
A(1, '1') // ok
A(1, 1) // 报错
函数类型
const A: (name: string) => void = fn1
const B: {
(name: string): void;
id: number;
} = fn2
type C = { // 函数重载
(): void;
(name: string): void
}
const D: {
id: number;
new (name: string): People;
} = People
枚举
enum Color {
One,
Two
}
Color.One === 0;
Color.Two === 1;
Color[0] === 'One'
Color[1] === 'Two'
any
anyscript === javascript
(笑
let value: any = 'akara'
value = 100 // 不报错
let num: boolean = value // 不报错
let obj: any = {}
obj.getName() // 不报错
unknown
unknown
表示某个变量的类型是未知的,也意味着这个变量可能是任意类型的值
let value: unknown;
let num: boolean = value // 报错!这里和any的表现不同
let obj: unknown = {
getName: function() {}
}
使用时通常搭配类型守卫来narrow
该变量的类型范围
let str: unknown;
if (typeof value === 'string') {
value.toString() // 被断言成string类型
}
never
function fn(value: 1 | 2) {
switch (value) {
case 1:
case 2:
return value;
default:
return neverThrow(value) // 此时value的类型为value。这种写法的好处是当其他人给联合类型时加类型时,此处会报错提醒
}
}
function neverThrow(value: never): never { // 函数永远不会返回值
throw new Error(`${value}`)
}