期望值是什么类型就赋值什么类型
基础类型
number、string、boolean、(Object、object、{})、array、null、undefined、 enum、tuple、any、unknown、void、symbol、never
null和undefined是所有类型的子类型,可以把null和undefined赋值其他任意类型any相当于暴力通过类型检查,可以被任意类型赋值,也可以赋值给任意类型unknown可以被任意类型赋值,但只能赋值给unknown和any类型的变量, ; 当进行了类型断言和类型推断之后,就可以赋值给其他任意类型的变量
function getAge() {
let x: unknown
return x
}
const age = getAge()
if (typeof age === 'string') {
const getAge = age.toLowerCase()
}
void常用函数返回值为空的情况
function getAge(): void {
console.log('没有返回值')
}
never常用来避免异常情况,目的就是写出类型绝对安全的代码
// 异常
function error(msg: string): never { // 编译正确
throw new Error(msg);
}
// 死循环
function loopForever(): never { // 编译正确
while (true) {};
}
数组
let arr: number[] = [1, 2, 3]
let arr1: Array<number> = [2, 4]
元组(Tuple),元组类型是方括号里放置不同的类型
let arr: [number, string, boolean] = [1, 'tuple', true]
object 、Object 、{}
- object object 类型用于表示所有的非原始类型,即我们不能把 number、string、boolean、symbol等 原始类型赋值给 object。在严格模式下,null 和 undefined 类型也不能赋给 object。
let object: object;
object = 1; // 报错
object = "a"; // 报错
object = true; // 报错
object = null; // 报错
object = undefined; // 报错
object = {}; // 编译正确
- Object
大 Object 代表所有拥有 toString、hasOwnProperty 方法的类型 所以所有原始类型、非原始类型都可以赋给 Object(严格模式下 null 和 undefined 不可以)
let bigObject: Object;
object = 1; // 编译正确
object = "a"; // 编译正确
object = true; // 编译正确
object = null; // 报错
ObjectCase = undefined; // 报错
ObjectCase = {}; // ok
- {}
{} 空对象类型和大 Object 一样 也是表示原始类型和非原始类型的集合
enum枚举
初始值默认为 0 其余的成员会会按顺序自动增长 可以理解为数组下标
enum Color {
RED,
PINK,
BLUE,
}
const red: Color = Color.RED;
console.log(red); // 0
- 设置初始值
enum Color {
RED = 2,
PINK,
BLUE,
}
const pink: Color = Color.PINK;
console.log(pink); // 3
- 字符串枚举
enum Color {
RED = "红色",
PINK = "粉色",
BLUE = "蓝色",
}
const pink: Color = Color.PINK;
console.log(pink); // 粉色
- 常量枚举
使用 const 关键字修饰的枚举,常量枚举与普通枚举的区别是,整个枚举会在编译阶段被删除 我们可以看下编译之后的效果
const enum Color {
RED,
PINK,
BLUE,
}
const color: Color[] = [Color.RED, Color.PINK, Color.BLUE];
console.log(color); //[0, 1, 2]
//编译之后的js如下:
var color = [0 /* RED */, 1 /* PINK */, 2 /* BLUE */];
// 可以看到我们的枚举并没有被编译成js代码 只是把color这个数组变量编译出来了
接口
我们常用接口的方式来表示对象的类型
interface Person {
name: string
age: number
readonly tel: string // 属性前面加 readonly 表示属性只读
height?: number // 属性后面加 ? 表示属性可选
[prop: string]: any // 在接口的末尾写方括号,prop类型表示其他任意类型
}
let obj: Person = {
name: '小明',
age: 18,
tel: '123456',
weight: 55, // 新增的属性
}
类型别名
type count = number | number[]
function hello(value: count) {}
函数
我们需要给各参数定义类型,也需要给函数的返回值定义类型
function add(x: number, y: number): number {
return x + y
}
// 参数后面加问号,表示类型可选
function add(x: number, y?: number): number {
return y ? x + y : x
}
// 在类型后面赋值,表示默认值
function add(x: number, y: number = 0): number {
return x + y
}
- 接口方式定义函数类型
interface Add {
(x: string, y: number): number
}
function add(x, y): Add {
return x + y
}
- 函数重载
type Types = number | string
function add(a: string, b: number): string
function add(a: number, b: string): string
function add(a: string, b: string): string
function add(a: number, b: number): number
function add(a: Types, b: Types) {
if (typeof a === 'string' || typeof b === 'string') {
return a.toString() + b.toString()
} else {
return a + b
}
}
const result = add('1', 2)
泛型
泛型的语法是尖括号 <>方式来定义泛型, 里面写类型参数(用大写字母来表示),如果式多个参数用逗号分隔
// 单个参数
function getName<T>(name: T): T {
return name
}
// 多个参数
function getValue<T, U>(arg: [T, U]): [T, U] {
return arg
}
泛型约束
对于泛型我们经常添加一些约束条件,比如参数必须具有length属性,我们可以用extends的方式来添加约束条件
interface LengthObj {
length: number
}
function getLength<T extends LengthObj>(arg: T): T {
return arg
}
const str = getLength('aaa')
const obj = getLength({
length: 5,
})
泛型接口
interface KeyValue<T, U> {
key: T
value: U
}
const person: KeyValue<string, number> = {
key: 'order',
value: 10,
}
联合类型
用 |(或)来表示联合
let value: number | string
value = 20
value = '联合类型'
交叉类型
用&来表示交叉类型
interface A {
name: string
age: number
}
interface B {
height: number
}
type AB = A & B
const person: AB = {
name: 'dale',
age: 18,
height: 180,
}
类型推断
如果我们定义一个变量赋值,没有定义类型,程序就会依据值的类型来推断类型。
如果定义一个变量没有赋值,程序就会推断为any类型
let x = 1
x = true // 报错,x 必须为 number类型
x = 2 // 成功
类型断言
let str: any = '尖括号来做类型断言也可以用as类型的方式来做类型断言'
const len: number = (<string>str).length
const lenAs: number = (str as string).length
非空断言
变量后面加!,表示变量不为空
let user: string | null | undefined
console.log(user!.toUpperCase())
确定赋值断言
let value:number
console.log(value); // Variable 'value' is used before being assigned.
我们定义了变量, 没有赋值就使用,则会报错
通过 let x!: number; 确定赋值断言,TypeScript 编译器就会知道该属性会被明确地赋值。
let value!:number
console.log(value); // undefined 编译正确
类型守卫
程序难以判断参数中是否包含某个属性,这时候如果直接使用的话,就会报错。这时候就需要我们手动推断。
in
interface A {
a: number
x: string
}
interface B {
a: number
y: string
}
interface C {
a: number
z: string
}
function getValue(arg: A | B | C) {
if ('x' in arg) {
console.log(arg.x)
}
if ('y' in arg) {
console.log(arg.y)
}
if ('z' in arg) {
console.log(arg.z)
}
}
typeof
function getValue(arg: number | string) {
if(typeof arg === "number") {
return 'number'
}
if(typeof arg === "string") {
return "string"
}
}
instanceof
function getValue(arg: Date | string) {
if (arg instanceof Date) {
return arg.getDate()
} else {
return new Date(arg).getDate()
}
}
内置工具类型
Record
record作用:是将对象所有的属性转化为需要的类型
// 使用 Record 将各属性都变成字符串类型,然后就可以直接赋值给其他变量
type Property = 'user1' | 'user2';
type User = Record<Property, string>
const u: User = {
user1: 'Da',
user2: 'Xia'
}
Readonly
作用:将数组和对象的属性值转化为只读
interface User {
name: string,
age: number
}
let u: Readonly<User> = {
name: 'Da',
age: 18
}
u.name = 'Xia' // 报错
Required
作用:将类型的所有属性都变为必选
interface A {
name?: string
age?: number
}
const user: Required<A> = {
name: 'a',
age: 18,
}
Partial
作用:将类型的所有属性都变为可选
interface A {
name: string
age: number
}
const user: Partial<A> = {}
Extract
作用:提取联合类型中的某些类型
type B = number | string | boolean | symbol
let value: Extract<B, number | string> = 1
Exclude
作用:移除联合类型中的某些类型
type B = number | string | boolean | symbol
let val: Exclude<B, number> = '1'
Pick
作用:从类型中挑出一些类型
Omit
作用:从类型中移除一些类型
NonNullable
作用:去除类型中的null和undefined
Parameters
作用:获取函数的参数类型,组成元组类型
ReturnType
作用:获取函数的返回值类型