目录
TypeScript类型
原始类型
number、boolean、string、null、undefined、symbol
String
let msg: string = 'Hello world!';
let msg2: String = 'Hello world!';
let msg22 = 'Hello world!'; // 字面上没有定义类型
let msg3: String = new String('Hello world!');
console.log(typeof(msg)); // string
console.log(typeof(msg2)); // string
console.log(typeof(msg22)); // string
console.log(typeof(msg3)); // object
console.log(msg === msg2); // true
console.log(msg === msg3); // false
console.log(msg2 === msg3); // false
与string的主要不同
1. 是一个String对象
2. 当使用eval()函数时,将被转换为字符串
let a: string = "3 * 9"
console.log(eval(a))
let b: String = new String("3 * 9")
// console.log(eval(b)) // Argument of type 'String' is not assignable to parameter of type 'string'
console.log(eval(b.toString()))
Array
const arr: string[] = ["aaa", "bbb", "ccc"]
const arr2: Array<string> = ["aaa", "bbb", "ccc"]
const arr3: (string | number)[] = ["aaa", 123]
如果添加其他类型到数组中会报错
Tuple
数组中通常建议存放相同类型的元素,而元组中每个元素都有自己特性的类型,根据索引值获取到的值可以确定对应的类型
const info: [string, number, boolean] = ["aaa", 123, true]
any
表示任意类型, 可以是一个集合,里面包含了所有的类型
const arr: any[] = ["aaa", 111, true]
unknown
表示是是所有类型的父级
用于描述类型不确定的变量
所有基础类型都能赋值给unknown类型
const flag = true
let result: unknown
if (flag) result = "aaa"
else result = 111
any与unknown区别
const valueUnknown: unknown = "a"
let str: string = "str"
// str = valueUnknown // 报错
const valueAny: any = 123
let str2: string = "str2"
str2 = valueAny
console.log(typeof str2) // number 改变了str2的类型
console.log(str2) // 123
never
表示的是那些永不存在的值的类型
例如一个抛出异常的函数,一个永远不会返回的函数的返回值类型
never 类型是任何类型的子类型,可以赋值给任意类型。但是没有类型是 never 类型的子类型,即使是 any 类型也不能赋值给 never 类型
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message)
}
// 推断的返回值类型为never
function fail() {
return error('Something failed')
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {}
}
void
用来指定一个函数没有返回值
可以将null或undefined赋值给void类型,也就是函数可以返回null或undefined
{}
描述了一个没有成员的对象
仍然可以使用在 Object 类型上定义的所有属性和方法,这些属性和方法可通过 JavaScript 的原型链隐式地使用
const typeObject: {} = {aaa: "aaa"}
// typeObject.aaa // 编译报错 Property 'aaa' does not exist on type '{}'
// console.log(typeObject["aaa"]) // 运行报错 Property 'aaa' does not exist on type '{}'
Object
类型 Object包括原始值
const obj: Object = "123" // OK
object
用于表示非原始类型
Object.create(proto); // OK
Object.create(null); // OK
Object.create(undefined); // Error
Object.create(1337); // Error
Object.create(true); // Error
Object.create("oops"); // Error
字面量类型
const text: "123" = "123"
一般与多个类型进行联合
type Alignment = "left" | "right" | "center"
类型断言as
有时候TypeScript无法获取具体的类型信息,这个时候我们需要类型断言
const myEl = document.getElementById("my-img") as HTMLImageElement
非空类型断言!
表示可以确定某个标识符是有值的,跳过ts在编译阶段对它的检测
枚举enum
枚举与字面量类型+联合类型组合的功能类似,都用来表示一组明确的可选值列表
enum Direction { Up, Down, Left, Right }
console.log(Direction.Up) // 0
类型别名type
type Point = {
x: number
y: number
}
可选类型?
在属性的后面添加?
可选类型可以看错是可选的类型和undefined的联合类型
联合类型 |
Union Type联合类型可以是由两个或者多个其他类型组成的类型
联合类型中的每一个类型被称为联合成员
类型A | 类型B | ......
匿名函数参数
当一个函数出现在TypeScript可以确定该函数会被如何调用的地方时,该函数的参数会自动指定类型
const strArr = ["aaa", "bbb", "ccc"]
strArr.forEach(item => {
console.log(item.toUpperCase())
})
我们没有指定item的类型,但是item是一个string类型,这是因为TypeScript会根据forEach函数的类型以及数组的类型推断出item的类型
这个过程称之为上下文类型(contextual typing),因为函数执行的上下文可以帮助确定参数和返回值的类型
类型保护与类型缩小
typeof
instanceof
in
平等缩小(===、!==)
this
1. 可以推导的this类型TypeScript不会报错
function sayHello() {
console.log(this.name)
}
const info = {
name: "why",
sayHello() {
console.log(this.name)
}
}
info.sayHello()
2. 不确定的this类型TypeScript会在编译时报错
function sayHello() {
console.log(this.name)
}
const info = {
name: "why",
sayHello
}
info.sayHello()
虽然我们能推导出来this的指向,但是对于TypeScript来说代码是非常不安全的,因为我们也有可能直接调用函数,或者通过别的对象来调用函数
3. 指定this的类型
type NameType = {
name: string
}
function sayHello(this: NameType) {
console.log(this.name)
}
函数的重载
function sum(a1: number, a2: number): number
function sum(a1: string, a2: string): string
function sum(a1: any, a2: any): any {
return a1 + a2
}
类
1. 类的成员修饰符
public:默认,任何地方都ok
private:同一类
protected:自身以及子类
2. 只读属性readonly,不能被修改
3. get set获取设置私有属性
接口interface
也可以定义只读属性readonly
支持多继承extends
定义后可以被类实现
交叉类型在接口上的应用
interface Colorful {
color: string
}
interface IRun {
running: () > void
}
type NewType = Colorful & IRun
const obj: NewType = {
color: "red",
running() {}
}
interface和type区别
interface可以重复对某个接口定义属性和方法,只能为对象指定类型
type定义的是别名,别名不能重复,可以为任意类型指定别名
freshness擦除
将一个变量标识符赋值给其他的变量时,会进行freshness擦除操作
interface IPerson {
name: string;
age: number;
eating: () => void;
}
const obj = {
name: "czc",
age: 22,
height: 175,
eating: function () {},
};
const person: IPerson = obj;
console.log(person); // { name: 'czc', age: 22, height: 175, eating: [Function: eating] }
// console.log(person.height); // Property 'height' does not exist on type 'IPerson'
泛型
// 泛型实现类型参数化
function foo<T, E>(a1: T, a2: E) {}
// 泛型接口
interface IFoo<T> {
initialValue: T,
valueList: T[],
handleValue: (value: T) => void
}
// 泛型类
class Point<T> {
x: T
y: T
constructor(x: T, y: T) {
this.x = x
this.y = y
}
}
// 泛型约束
interface ILength {
length: number
}
function getLength<T extends ILength>(args: T) {
return args.length
}
模块化开发
TypeScript支持两种方式来控制我们的作用域
模块化:每个文件可以是一个独立的模块,支持ES Module、CommonJS
命名空间:通过namespace来声明一个命名空间
export namespace Time {
export function format(time: string){
return "2022-06-11"
}
}
声明declare
declare可以向TypeScript域中引入一个变量,在编写代码的时候就能够实现智能提示的功能
.d.ts 文件中的顶级声明必须以 "declare" 或 "export" 修饰符开头。
通过declare声明的类型或者变量或者模块,在include包含的文件范围内,都可以直接引用而不用去import或者import type相应的变量或者类型。
// 声明变量-函数-类
declare let wName: string
declare function wFoo(): void
declare class Person {}
// 声明模块
// 我们也可以声明模块,比如lodash模块默认不能使用的情况,可以自己来声明这个模块
// 在声明模块的内部,我们可以通过 export 导出对应库的类、函数等
declare module "lodash" {
export function join(args: any[]): any
}
// 声明文件
// 比如在开发vue的过程中,默认是不识别我们的.vue文件的,那么我们就需要对其进行文件的声明
declare module "*.vue" {
import { DefineComponent } from "vue"
const component: DefineComponent
export defualt component
}
// 声明命名空间
// 比如我们在index.html中直接引入了jQuery
declare namespace $ {
function ajax(settings: any): void
}
参考资料
深入Vue3+TypeScript技术栈-coderwhy大神新课-学习视频教程-腾讯课堂
【TS】566- 一文读懂 TS 中 Object, object, {} 类型之间的区别_pingan8787的博客-CSDN博客