目录
- 声明文件
- 类型推论
- 联合类型
- 交叉类型
- 类型断言
- 内置类型
- 类型别名
- keyon in
- 基本类型
- interface
- class
- 泛型
基础类型
/**************基本数据类型***************/
// 表示任务是否完成的布尔变量
let isTaskCompleted: boolean = false;
// 表示年龄的数字变量
let userAge: number = 10;
// 表示用户姓名的字符串变量
let userFirstName: string = 'WangZha';
// 使用模板字符串定义的问候信息字符串变量
let greetingMessage: string = `Hello ${userFirstName}`;
// 未定义类型的变量,值为undefined
let undefinedVar: undefined = undefined;
// null类型的变量
let nullVar: null = null;
// 字符串类型的变量,初始值为null
let userName: string = null;
// 任意类型的变量,初始值为5
let anyVar: any = 5;
// 任意类型可以随意更改,相当于没有设置类型
anyVar = 'maybe a string';
// 更改anyVar的值为布尔值true
anyVar = true;
// 尝试访问anyVar的myName属性,由于anyVar现在是true,所以会引发类型错误
// anyVar.myName;
// 尝试调用anyVar的getName()方法,同样会引发类型错误
// anyVar.getName();
// 数字类型的数组定义
let numbersArray: number[] = [1, 2, 3];
// 在数组末尾添加元素4
numbersArray.push(4);
console.log(numbersArray); // [1,2,3,4]
// 只能在数组中添加数字类型的元素
// numbersArray.push('wangzha'); // 报错
tuple ( 元祖 )
let user: [string,number] = ['wangzha',18]
user = ['wangzhas',20]
function
// 函数定义的几种方式
// 1. 常规函数声明
function addNumber(x: number, y: number, z?: number): number {
// z 参数是可选的,?:number 表示它是一个可选参数,类型为 number
return x + y; // 返回两个数字的和
}
addNumber(1, 6); // 调用该函数,因为 z 是可选的,所以这里不需要提供第三个参数
// 2. 箭头函数声明
let addNumber2 = (x: number, y: number) => {
return x + y; // 返回两个数字的和
}
// 3. 使用具名函数表达式
const addNumber2: (x: number, y: number, t?: number) => number = addNumber; // 这里定义了一个名为 addNumber2 的常量,它是一个函数,该函数接受两个数字和一个可选的数字,并返回一个数字。这个函数被赋值为 addNumber。
// interface
interface FunctionProps {
// 这是一个方法接口,它描述了一个名为 FunctionProps 的对象应该具有的方法。这个方法接受两个参数:一个数字和一个字符串,并返回一个数字或字符串。
(x: number, y: string): number | string;
// name 属性是一个字符串类型。
name: string;
// age 属性是一个数字类型。
age: number;
}
接口 interface
interface是一种定义对象结构的语法糖。它允许你定义对象的形状,并确保对象具有某些属性或方法。
// 定义一个Person接口,包含id、name和可选的age属性
interface Person {
readonly id: number;
name: string;
age?: number;
}
// 创建一个Person对象,包含name、age和id属性
let xiaoming: Person = {
name: 'xiaoming',
age: 20,
id: 1
}
// 定义一个函数sum,接受两个数字参数,返回它们的和
const sum = (x: number, y: number) => {
return x + y
}
// 定义一个ISum接口,要求实现一个函数,接受两个数字参数并返回数字类型的结果
interface ISum {
(x: number, y: number): number
}
// 将sum函数赋值给sum2变量,使sum2满足ISum接口的要求
const sum2: ISum = sum
// 定义一个RandomMap接口,要求实现一个对象,其属性名是字符串类型,属性值也是字符串类型
interface RandomMap {
[propName: string]: string;
}
// 创建一个RandomMap对象,包含a、b和c属性,分别赋值为hello、test和test
const test: RandomMap =
a: 'hello',
b: 'testb',
c: 'testc'
}
// 定义一个LikeArray接口,要求实现一个对象,其索引是数字类型,值是字符串类型
interface LikeArray {
[index: number]: string
}
// 创建一个LikeArray对象,包含1、2和3属性,分别赋值为'1'、'2'和'3'
const likeArray: LikeArray = ['1', '2', '3']
// duck typing(鸭子类型):只检查对象是否有需要的属性或方法,而不关心这些属性的具体定义是什么。这是通过类型断言实现的。
// 定义一个FunctionWithProps接口,要求实现一个函数和一个name属性。函数接受一个数字参数并返回数字类型的结果。name属性是字符串类型。
interface FunctionWithProps {
(x: number): number;
name: string;
}
// 创建一个FunctionWithProps对象,包含一个函数和一个name属性。函数接受一个数字参数并返回该参数。name属性被赋值为'abc'。注意这里没有显式地声明函数返回值类型,TypeScript会自动推断出返回值类型为number。同时也没有显式地声明name属性类型,TypeScript会自动推断出name属性类型为string。这就是duck typing的特性。
const a: FunctionWithProps = (x: number) => {
return x
}
a.name = 'abc'
泛型 <>
泛型是一种让用户定义可重用的组件,而不需要为各种数据类型编写重复的代码的特性。通过使用泛型,您可以在编写代码时指定一个或多个类型参数,这些类型参数在组件的整个生命周期中都会被保留。
/************************* 基础泛型 *************************/
// 定义一个泛型函数 echo,它接受一个类型为 T 的参数 arg,并返回一个类型也为 T 的结果。
function echo<T>(arg: T): T {
return arg;
}
// 使用 echo 函数,传入字符串 'xiaoming',并将返回的结果赋值给常量 each。
const each = echo('xiaoming');
// 定义一个泛型函数swap,它接受一个由两个类型分别为T和U的元素组成的元组,并返回一个元组,其元素顺序与输入元组相反。
function swap <T, U>(tuple: [T, U]): [U, T] {
// 使用数组解构的方式来颠倒元组中的元素顺序。
return [tuple[1], tuple[0]];
}
// 调用swap函数,并传入一个元组['string', 123]。此元组的类型为[string, number]。
// 函数会返回一个新的元组[123, 'string'],其类型为[number, string]。
const result = swap(['string', 123]); // 正确的调用方式
// 定义一个名为 CountryResp 的接口,用于描述国家响应数据的结构
interface CountryResp {
name: string; // 国家的名称,数据类型为字符串
area: number; // 国家的面积,数据类型为数字
population: number; // 国家的人口数量,数据类型为数字
}
// 定义一个泛型函数 withAPI,它接受一个 URL 字符串作为参数,并返回一个 Promise 对象
// T 是泛型参数,表示这个函数可以处理任何类型的数据
function withAPI<T>(url: string): Promise<T> {
// 使用 fetch API 从给定的 URL 获取数据,然后将其解析为 JSON 格式
// 最后返回解析后的 JSON 数据(类型为 T)的 Promise 对象
return fetch(url).then(resp => resp.json())
}
// 调用 withAPI 函数,并指定返回数据的类型为 CountryResp
// 传入 'country.resp' 作为 URL 参数来获取国家数据
withAPI<CountryResp>('country.resp').then(resp => {
// 在这里处理获取到的国家数据
// 例如,打印出国家的名称
console.log(resp.name);
})
/************************* 类中的泛型 *************************/
class Matrix<T> {
private elements: T[][] = [];
constructor(elements: T[][]) {
this.elements = elements;
}
getElement(i: number, j: number): T {
return this.elements[i][j];
}
setElement(i: number, j: number, element: T) {
this.elements[i][j] = element;
}
}
// Create a matrix of strings.
const matrix1 = new Matrix<string>([["a", "b"], ["c", "d"]]);
/************************* 泛型约束 *************************/
// 关键字:extends
// extends关键字用于表示一个类继承另一个类。
// 通过使用extends,子类可以继承父类的属性和方法,并且可以添加或覆盖父类的实现。
interface IWithLength {
length:number
}
// extends in generice
function echoWithArr<T extends IWithLength>(arg:T):T {
console.log(arg.length);
return arg
}
const arrs = echoWithArr([1, 2, 3])
const str = echoWithArr('123')
const obj = echoWithArr({length: 123, width: 'hello' })
// 定义一个泛型类型 NonType,它接受一个类型参数 T。
// 如果 T 是 null 或 undefined,则 NonType 的类型是 never;否则,NonType 的类型就是 T。
type NonType<T> = T extends null | undefined ? never : T;
// 定义一个变量 demo1,其类型为 NonType<number>。
// 因为 number 不是 null 或 undefined,所以 demo1 的类型是 number。
let demo1: NonType<number>;
// 定义一个变量 demo2,其类型为 NonType<null>。
// 因为 null 是 null 或 undefined,所以 demo2 的类型是 never。
let demo2: NonType<null>;
类 class
/************** es 类的基础使用***************/
// 定义一个动物类
// 包含受保护的动物名称属性
class Animal {
// 受保护的动物名称,只能在Animal类内部和继承Animal类的子类中访问
protected animalName: string;
// 构造函数,接收一个动物名称参数,并将其赋值给animalName属性
constructor(animalName: string) {
this.animalName = animalName;
}

// 定义一个run方法,返回一个字符串,表示动物正在奔跑
run() {
return `${this.animalName} is running`;
}
}
// 创建一个Animal类的实例,名为snake,并传入Lily作为参数
const snake = new Animal('Lily');
// 调用snake对象的run方法,输出Lily is running
snake.run();
// 定义一个Dog类,继承自Animal类
class Dog extends Animal {
// 定义一个bark方法,返回一个字符串,表示狗正在吠叫
bark() {
return `${this.animalName} is barking`;
}
}
// 创建一个Dog类的实例,名为xiaobao,并传入Xiaobao作为参数
const xiaobao = new Dog('Xiaobao');
// 调用xiaobao对象的run方法,输出Xiaobao is running
xiaobao.run();
// 定义一个Cat类,继承自Animal类
class Cat extends Animal {
// 重写Animal类的构造函数,接收一个catName参数,并调用父类的构造函数,同时输出animalName的值
constructor(catName: string) {
super(catName);
console.log(this.animalName);
}
// 定义一个run方法,返回一个字符串,表示猫正在发出“Meow”的声音,并调用父类的run方法
run() {
return 'Meow, ' + super.run();
}
}
// 创建一个Cat类的实例,名为maomao,并传入Maomao作为参数
const maomao = new Cat('Maomao');
/************** ts 中使用 ***************/
//implements关键字用于表示一个类实现了某个接口。接口是一种定义对象结构的方式,而类则是一种实现这种结构的实例。通过使用 `implements` 关键字,你可以确保类遵循特定接口的所有要求和属性。
interface TimerInterface {
currentCountdown: number;
startCountdown(): void;
}
interface TimerStatic {
new(seconds: number): void;
countdownTime: number;
}
interface GameInterface {
play(): void;
}
const Timer: TimerStatic = class Timer implements TimerInterface {
constructor(seconds: number) {
this.currentCountdown = seconds;
}
static countdownTime = 120; // 120秒倒计时,可根据实际需要进行修改
currentCountdown: number = 0; // 初始化为0,可以在构造函数中进行计算和设置
startCountdown() {
// 启动倒计时逻辑(可以在此处添加具体实现)
}
}
class GameDevice implements TimerInterface, GameInterface {
currentCountdown: number = 0; // 初始化为0,可以在构造函数中进行计算和设置
startCountdown() {
// 启动倒计时逻辑(可以在此处添加具体实现)
}
play() {
// 播放游戏音效或启动游戏逻辑(可以在此处添加具体实现)
}
}
类型别名
在 TypeScript 中,类型别名(Type Aliases)是一种用于给复杂类型命名的机制。类型别名可以让代码更加简洁和可读,并使类型定义更加模块化和可重用。
要定义一个类型别名,可以使用 type 关键字,后面跟上别名名称和类型声明
// 类型别名 - 为sum变量定义了一个类型别名,该类型别名表示一个接受两个数字参数并返回一个数字的函数
let sum: (x: number, y: number) => number
// 使用sum函数计算1+2的结果,并将结果存储在result变量中
const result = sum(1,2)
// 类型别名 - 定义了一个类型别名addType,它表示一个接受两个数字参数并返回一个数字的函数
type addType = (x: number, y: number) => number
// 为sum2变量定义了PlusType类型别名
let sum2: addType
// 使用sum2函数计算1+2的结果,但不将结果存储在任何变量中
sum2(10, 12)
联合类型 |
let numberOfString: number | string;
交叉类型 &
interface PersonName {
name:string
}
type PersomOrAge = PersonName & {age:number}
let person:PersomOrAge = {
name:'wangzha',
age:19
}
类型断言 as
function getLength(input: number | string) {
const str = input as string
if (str.length) {
return str.length
} else {
const number = input as number
return number.toString().length
}
}
高级用法 keyof in
keyof 是一个类型操作符,用于获取一个类型的所有键(属性名)组成的联合类型。keyof 可以用于对象类型、接口类型或类型别名。
keyof 与映射类型:
// 定义一个名为 CountryResp 的接口,用于描述国家的信息 interface CountryResp { name: string; // 国家名称,字符串类型 area: number; // 国家面积,数字类型 population: number; // 国家人口,数字类型 }
// 使用 keyof 操作符获取 CountryResp 接口的所有属性名,组成一个新的类型 Keys // 这里的 Keys 将是一个只包含 'name', 'area', 'population' 的字符串字面量类型 type Keys = keyof CountryRes
// 使用映射类型 (mapped types) 创建一个新的类型 NameType,其属性名与 CountryResp 相同,但值类型为 NameType['name'] type NameType = { [P in Keys]?: CountryResp[P] extends string ? P : never }[Keys]
// 使用映射类型创建一个新的类型 Test,其属性名与 Keys 相同,但值类型为 any,意味着不限制属性的具体类型 type Test = { [key in Keys]: any }
// 使用可选链和映射类型创建一个新的类型 CountryOpt,其属性名与 Keys 相同,但值类型为可选的 CountryResp 属性类型 type CountryOpt = { [p in Keys]?: CountryResp[p] | undefined }

## React 函数组件源码分析

## 定义一个 index.d.ts 文件
将定义好的 `index.d.ts` 放置到 `node_modules/@types/xxx文件名/index.d.ts`
```typescript
type HTTPMethod = 'GET' | 'POST' | 'PATCH' | 'DELETE'
declare function myFetch<T = any>(url: string, method: HTTPMethod, data?: any) : Promise<T>
declare namespace myFetch {
const get: <T = any>(url: string) => Promise<T>;
const post: <T = any>(url: string, data: any) => Promise<T>;
}
export = myFetch
备注:以上内容参考于慕课网架构师系列教程