Typescirpt
想必大家已经知道Typescript有什么作用了,话不多说,直接开整,
此文为本人入门学习笔记,有谬误和缺漏欢迎指出
目录
基本使用
八大类型
let str: string = "jimmy";
let num: number = 24;
let bool: boolean = false;
let u: undefined = undefined;
let n: null = null;
let obj: object = {x: 1};
let big: bigint = 100n;
let sym: symbol = Symbol("me");
// 注意
// 大写首字母,指的是包装类型
let isDoneToo: Boolean = new Boolean(1)
// console.log(typeof isDoneToo); // object
类型扩宽
看了上面基础使用的小伙伴肯定心里犯嘀咕了. 这么麻烦?定义一个变量就要写一次类型,这不得累死. 而且const 又不用修改,类型一目了然,
接下来我们介绍 类型扩宽
let str1 = "this is string" // 类型是 string
const str2 = "this is string" // 类型是 "this is string"
注意观察 st1 和 str2 类型不同
// 这个东西有什么用呢? 举个例子:
function getComponent(axis: 'x' | 'y' | 'z') {
return axis
}
let y = 'y'
getComponent(y) // 类型“string”的参数不能赋给类型“"x" | "y" | "z"”的参数。ts(2345)
// 需要把let 改成 const , const 的类型是 'y',才符合要求
// 使用 const 类型断言, 取消类型扩宽
// Type is { x: number; y: number; }
const obj1 = {
x: 1,
y: 2
};
// Type is { x: 1; y: number; }
const obj2 = {
x: 1 as const,
y: 2,
};
// Type is { readonly x: 1; readonly y: 2; }
const obj3 = {
x: 1,
y: 2
} as const;
void
用来表示没有任何返回值的函数
let a: void = undefined
function fnn(): void { }
never
表示永远不会存在值的类型
function fnnn(): never {
while (true) {
}
}
// 用法
// 利用 never 类型的特性来实现全面性检查
type Foo = string | number;
function handleValue(foo: Foo) {
if (typeof foo === "string") {
// 这里 foo 被收窄为 string 类型
} else if (typeof foo === "number") {
// 这里 foo 被收窄为 number 类型
} else {
// 永远到达不了
const check: never = foo;
// 如果达到这里就会报错, 因为 never类型不能赋值
}
}
Never 和 Void 的 区别
虽然他们看上去没什么区别,都可以用于描述函数没有返回值
但我们默认 没有显式返回值的函数会隐式返回 undefined 。 注意: never类型可以被undefined 赋值
具有never返回类型的函数永不返回,它也不返回 undefined。 注意: 返回never的函数必须存在无法达到的终点
unknown
用来描述我们不知道类型的变量
let maybe: unknown
maybe = 1
maybe = '2'
maybe = {}
Unknow 和 Any 的区别
推荐使用unknown, 如果是any类型, 相当于放弃了类型检查
let maybe2: unknown;
maybe2 = [1, 2, 3, 4]
// console.log(maybe2.length); // 报错报错报错. 必须进行类型收窄, 如果maybe2 是 any类型就不会报错
if (maybe2 instanceof Array) {
// console.log(maybe2.length); // 4
}
类型断言
// 尖括号 语法
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
// as 语法
let someValue1: any = "this is a string";
let strLength2: number = (someValue1 as string).length;
联合类型
let b: string | number
function say(age: string | number) {
age.toString()
// age.length // 报错,当ts不确定是哪种类型, 此时只能访问联合类型共有的属性和方法
// 当变量赋值后, 会根据类型推断出一个类型
}
数组的类型
类型 + []
数组项中不能出现其他类型, 调用方法添加也不行
const list: number[] = [1, 2, 3]
// 针对一些复杂的数组, 我们可以通过any 来表示数组中允许出现任意的类型
const listTwo: any[] = ['1', 2, { username: 'nzk', age: 18 }]
interface Arrobj{
name:string,
age:number
}
let arr3:Arrobj[]=[{name:'jimmy',age:22}]
// 联合类型的数组
let arr:(number | string)[];
// 表示定义了一个名称叫做arr的数组,
// 这个数组中将来既可以存储数值类型的数据, 也可以存储字符串类型的数据
arr = [1, 'b', 2, 'c'];
数组泛型写法
const listThree: Array<string> = ['1', '2', '3']
接口表示
interface NumberArray {
[index: number]: number
}
const list4: NumberArray = [1, 2, 3]
元组(Tuple)
const Tuple: readonly[number, string, boolean?, ...object[]] = [1, '2', true, {}, {}, {}]
枚举 (enum )
// 会自动递增
enum Days {
Mon = 1,
Tue,
Wed,
Thu,
Fri,
Sat,
Sun,
}
Days['Mon'] // 1
Days['Sun'] //7
// 常量枚举
const enum Month {
Jan,
Feb,
Mar,
// April = '123'.length // 会报错, 计算项不能出现在常量枚举中
}
// 外部枚举
declare enum Directions {
Up,
Down,
Left,
Right
}
类型 (type)
type 和 interface 的区别
type
- 不允许同名, 扩展已有的
type
需要创建新type
interface
-
同名会合并
-
只能表示
object
、class
、function
类型
接口 interface
interface Duck {
// 只读属性,不能修改
readonly id: number,
name: string
age: number
// 可选属性
gender?: boolean
walk: Function
//任意属性 如果定义了任意属性,那么上面确定属性和可选属性必须是它的子集
[propName: string]: string | number | boolean | Function | undefined
}
const dog: Duck = {
id: 1,
name: '乌子',
age: 11,
walk() { },
color: 'red'
}
函数的类型
const sum = function (x: number, y: number): number {
return x + y
}
// 上面的 sum 左侧是类型推导出来的
// 手动添加类型如下所示
// 这里的 => 与es6的箭头不同, ts 中 => 用来表示函数的定义, 左边是输入类型, 右边是输出类型
const sumCopy: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y
}
或使用接口
interface ISumFunc {
(firstName: string, lastName?: string): string
}
const buildName: ISumFunc = (firstName, lastName) => firstName + '' + lastName
剩余参数
设有默认值的参数,默认为可选参数
通过…rest 的方式获取函数中剩余的参数, 它只能作为函数的最后一个参数
function getRest(first: any = '999', ...rest: any[]) {
rest.map(el => { })
}
getRest(1, 2, 3, 4, 5, 6)
函数重载
function add(x: number, y: string): void
function add(x: string, y: number): void
function add(x: string | number, y: number | string): void { }
add(1, '1')
add('2', 2)
// add('2', '2') 报错,传入的参数必须符合前面的定义
泛型
T 类型 K 键 V值
泛型就是解决 类 接口 方法的复用性, 以及对不特定数据类型的支持(类型校验)
function getData<T>(value: T): T {
return value
}
console.log(getData<number>(123));// 调用的时候给泛型写上类型
getData(123) // 也可以不写,自动推断
typeof
// 在类型上下文中获取变量或者属性的类型
const sem: Person = { name: "nzk", age: 30 }
type Sem = typeof sem // type Sem = Person
const semTwo = { name: "nzk", age: 30 }
type SemTwo = typeof semTwo
// type SemTwo = {
// name: string;
// age: number;
// }
// 它也可以用来获取函数对象的类型
keyof
该操作符可以用于获取某种类型的所有键,其返回类型是联合类型。
// 使用keyof
function propTwo<T extends object, K extends keyof T>(obj: T, key: K) {
return obj[key]
}
type Any = keyof any // type Any = string | number | symbol
in
in用来遍历枚举类型
type Keys = 'a' | 'b' | 'c'
type Obj = {
[p in Keys]: string
}
/*
type Obj = {
a: string;
b: string;
c: string;
}
*/
infer
用于占位
type ReturnType<T extends (...any: any) => any> =
T extends (...any: any) => infer R ? R : any
type Parameters<T extends (...param: any) => any> =
T extends (...param: infer P) => any ? P : any
// 以上两个工具类型, 通过 infer 占位设置一个泛型 获取到了参数或返回值的类型, 用于获取未知的类型
// 将元组转化成联合类型
type ElementOf<T> = T extends Array<infer E> ? E : never
type TTuple = [string, number]
type ToUnion = ElementOf<TTuple> // string | number
extends
映射类型
interface TestInterface {
name?: string,
age?: number
}
// 通过+/-来指定添加还是删除
type OptionalTestInterface<T> = {
readonly [p in keyof T]-?: T[p]
}
type newTestInterface = OptionalTestInterface<TestInterface>
/*
type newTestInterface = { // 所有类型都变成必选,只读
readonly name: string;
readonly age: number;
}
*/
内置工具类型
由于一些功能需求比较常见, ts内置一些工具类型
Partial
/*
type Partial<T> = {
[P in keyof T]?: T[P];
}
*/
interface UserInfo {
id: string,
name: string,
age: number,
love: string
}
type NewUserInfo = Partial<UserInfo> // 所有属性变为可选
const xiaoming: NewUserInfo = {
name: 'nzk'
}
// 一个递归的 Partial
type DeepPartial<T> = {
// 如果是 object,则递归类型
[U in keyof T]?: T[U] extends object
? DeepPartial<T[U]>
: T[U]
};
// type PartialedWindow = DeepPartial<T>; // 现在T上所有属性都变成了可选啦
Required
与Partial
同理
Readonly
与partial
同理
Pick
从某个类型中取出一些属性形成一个新的类型
type MyPick<T, K extends keyof T> = {
[P in K]: T[P]
}
type NewNzkINfo = MyPick<UserInfo, 'id' | 'name'>
/*
type NewNzkINfo = {
id: string;
name: string;
}
*/
const nzk: NewNzkINfo = {
id: '1',
name: 'nzk'
}
Record
Record <作为K的type, 作为Value的type> 形成一个新的类型
type Any = keyof any // type Any = string | number | symbol
type Record<K extends string, T> = {
[P in K]: T;
}
interface PageInfo {
title: string
}
type Page = "home" | "about" | "contact"
/*
Record <作为K的type, 作为Value的type>
*/
type Xone = Record<Page, PageInfo>
/* type Xone = {
home: PageInfo;
about: PageInfo;
contact: PageInfo;
} */
const xone: Xone = {
about: { title: "aaaa" },
contact: { title: "cccc" },
home: { title: "hhhh" },
}
Omit
/*
Omit<T, K extends keyof any> 的作用是使用 T 类型中除了 K 类型的所有属性,来构造一个新的类型。
简单说就是删除一(多)个属性
*/
type MyOmit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Omit<Todo, "description">;
const todoTwo: TodoPreview = {
title: "Clean room",
completed: false,
};
/*
步骤分解
*/
// 先使用 Exclude 删掉 Todol联合类型中的 description
type step1 = Exclude<keyof Todo, 'description'> // type step1 = "title" | "completed"
// 再使用 Pick将 剩下的联合类型组成需要的类型别名
type step2 = Pick<Todo, step1>
/*
type step2 = {
title: string;
completed: boolean;
}
*/
ReturnType
获取函数的返回值类型
type ReturnType<T extends (...args: any[]) => any>
=
T extends (...args: any[]) => infer R ? R : any;
Parameters
获取函数类型中的参数部分,作为一个元组返回
const fn1 = (name:string,age:number,love?:string) => {
return {
name,
age
}
}
type Fn2 = Parameters<typeof fn1>
// type Fn2 = [name: string, age: number, love?: string | undefined]
const fn2 = ([name,age]:Fn2) =>{
const username = "名字" + name
fn1(username,age)
}
类
class Person{
name: string = "孙悟空"
static subName: string = "美猴王" // 静态属性 访问必须要通过 Person
static get init ():void { // 带get的会立即执行 ???
console.log("立即执行")
}
}
Person.subName
Person.init
在类的方法中,super表示当前类的父类
继承时,必须要写super(); 如果父类有参数
constructor(父类xxx:string){
super(父类xxx)
}
类的继承,详情见 /TS/day01/src/类.ts
abstract
:开头的类是抽象类,只能用于继承,不能实例化
public
:公有属性
private
:私有属性,属性名前加 private 禁止被修改 只能在内部访问,如果要访问和修改,都得通过方法
protected
: 保护类型, 只有当前类和子类能访问, 外部不能访问
装饰器
function logClass(param: string) {
// param 是当前的类
// param.prototype.apiUrl = "动态扩展的属性"
return function(target:any){ // 装饰器工厂
console.log(target);
console.log(param);
}
}
@logClass('hello')
class Http {
value: number
constructor(value: number) {
this.value = value
}
}
const http = new Http(1)
console.log(http);
其他
.d.ts
JS文件 + .d.ts文件 === ts文件
.d.ts 文件可以让JS文件继续维持自己JS文件的身份, 而拥有TS的类型保护.