深入理解 TypeScript:从入门到熟悉

目录

一、什么是 TypeScript以及为什么使用TypeScript?

二、TypeScript基础

三、高级TypeScript 

四、TypeScript和React的结合

五、ts常见面试题


一、什么是 TypeScript以及为什么使用TypeScript?

TypeScript是JavaScript的超级,可以编译为js。相比js添加了静态类型和其他一些新特性。例如:

  • ts通过引入静态类型,开发人员可以在编译时就捕获一些常见的错误,例如类型不匹配以及变量未定义等,这可以减少在运行时出现的错误,提高代码的可读性和可维护性。
  • ts提供了强大的开发工具支持(代码补全、代码导航等),可以提高开发效率,并帮助开发人员更好的理解和修改代码。
  • ts支持模块化开发,可以将代码分割成多个模块,提供更好的代码组织和可维护性。
  • Ts 还支持面向对象编程的概念,如类、接口、继承等,可以更好地组织和抽象代码。
  • TypeScript 是 JavaScript 的超集,这意味着现有的 JavaScript 代码可以逐步迁移到 TypeScript,而无需一次性重写整个代码库。这种渐进式采用使得 TypeScript 在现有项目中的集成更加容易。

二、TypeScript基础

1、ts的基本类型(Boolean, Number, String, Array, Tuple(元组), Enum(枚举值), Any, Void, Null , Undefined, Never)

2、ts中的变量声明、类型注解以及类型推断

  • 变量声明:在ts中,跟在js一样,可以使用let和const来声明变量。
  • 类型注解:类型注解是指在变量或函数参数后面使用(:)来指定变量的类型,例如let aa:number = 1。类型注解可以帮助ts编译器检查代码的类型正确性
  • 类型推断:可以根据变量的赋值表达式自动推出变量的类型,而无需显式指定类型注解,例如let num = 10会自动推断num为number类型。

类型注解可以提供更明确的类型信息,增强代码的可读性和可维护性,而类型推断则可以简化代码,减少不必要的类型注解

3、接口(interface):TypeScript 支持接口,用于定义对象的结构。接口可以描述对象的属性、方法和索引签名,并可以被类、函数和其他接口实现。

//定义一个接口
interface aa {
    num:number,
    boo:boolean,
    ...
}

4、别名(type):我们可以使用type为复杂的类型定义一个新的名称,使代码更具可读性。type可用于原始类型、联合类型、交叉类型、元祖、字面量类型等。type不能创建一个新的类型,它只是为已存在的类型定义一个新的名称。

//1、为原始类型定义别名
type Name = string;

//2、为复杂类型定义别名
type User = {
  name: string;
  age: number;
}

//3、为联合类型定义别名
type StringOrNumber = string | number;

//4、为交叉类型定义别名
type TallAndHandsome = Tall & Handsome;

//5、为元组定义别名
type Point = [number, number];

//6、为字面量类型定义别名
type YesOrNo = 'yes' | 'no';

5、可选参数:ts支持可选参数,用问号(?)标记,例如 interface aa{num?:number}

6、ts中函数的基本用法:

//1、函数类型声明
function add(x: number, y: number): number {
  return x + y;
}
//2、可选参数 必须位于所有必填参数后面
function greet(name: string, greeting?: string): string {
  return `${greeting}, ${name}`;
}
//3、函数类型
type MyFunc = (x: number, y: number) => number;

//4、函数重载,允许你为同一个函数名定义多个函数类型,然后,TypeScript 会根据提供的参数类型选择正确的函数实现
function add(a: string, b: string): string;
function add(a: number, b: number): number;
function add(a: any, b: any): any {
  if (typeof a === 'string' && typeof b === 'string') {
    return a + b;
  } else if (typeof a === 'number' && typeof b === 'number') {
    return a + b;
  }
}

7、ts中的类

//1、简单的类的定义和使用
class Person {
  name: string;  // 定义了一个名为 name 的属性,类型为 string
  age: number;   // 定义了一个名为 age 的属性,类型为 number

  constructor(name: string, age: number) {  // 类的构造函数,用于初始化类的属性
    this.name = name;
    this.age = age;
  }

  greet() {  // 定义了一个名为 greet 的方法
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
}

let john = new Person('John', 25);  // 创建一个 Person 类的实例
john.greet();  // 调用 greet 方法

//2、ts中类的继承
class Employee extends Person {
  company: string;

  constructor(name: string, age: number, company: string) {
    super(name, age);  // 调用父类的构造函数
    this.company = company;
  }

  greet() {
    super.greet();  // 调用父类的 greet 方法
    console.log(`I work at ${this.company}.`);
  }
}

let jane = new Employee('Jane', 30, 'Google');
jane.greet();

8、联合类型、交叉类型以及索引类型

  • 联合类型是ts中的一种复合类型,表示一个值可以是几种类型之一。我们用竖线(|)分隔每个类型。例如:type aa = string|number
  • 交叉类型是将多个类型合并为一个类型,我们用(&)连接起来。
  • 索引类型允许你通过索引类型查询和索引访问操作符来操作对象的属性和属性值的类型,例如
interface Person {
  name: string;
  age: number;
}

type PersonKeys = keyof Person; // 'name' | 'age'
type PersonValues = Person[PersonKeys]; // string | number

三、高级TypeScript 

1、泛型:在ts中,泛型是一种创建可重用的组件的强大工具,它可以在多种类型间进行工作,而不是单一类型。泛型的主要目的是提供类型安全的方式来使用和操作任何类型的数据。泛型可以用于函数、类、接口等。

//1、泛型函数
function identity(arg:T):T{
    return arg
}
let output = identity("myString") //指定T为string类型

//2、泛型类
class GenericNumber {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

//3、泛型接口
interface GenericIdentityFn {
    (arg: T): T;
}
let myIdentity: GenericIdentityFn

2、映射类型:映射类型允许你从旧的类型中创建新的类型,例如你想要一个新的类型,它具有旧类型的所有属性,但每个属性都是只读。则可以使用映射类型。ts内置的工具类型Pick、Partial、Required、Readonly等都是利用映射类型实现的。

//创建一个新的子类型,此类型从 T 中挑选出一组属性 K
type Pick = {
    [P in K]: T[P];
};
//创建一个新的子类型,此类型将 T 中的所有属性都变为可选
type Partial = {
    [P in keyof T]?: T[P];
};
//创建一个新的子类型,此类型将 T 中的所有属性都变为必需
type Required = {
    [P in keyof T]-?: T[P];
};
//创建一个新的子类型,此类型将 T 中的所有属性都变为只读
type Readonly = {
    readonly [P in keyof T]: T[P];
};

3、条件类型:条件类型可以让你根据一个条件表达式选择两种可能的类型。它的语法是T extends U ? X : Y。如果T可以赋值给U,那么类型是X,否则是Y。例如你想实现从一个类型中提取出所有的函数,则可以使用条件类型。ts内置的工具类型Exclude、Extract、Parameters等都是利用条件类型实现的。

//从一个类型中提取出所有的函数
type ExtractFunction = {
    [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
}

//创建一个新的类型,只包含 T 中那些不能赋值给 U 的类型 Exclude<'a' | 'b' | 'c', 'a' | 'b'> ===> 'c'
type Exclude = T extends U ? never : T;

//它创建一个新的类型,只包含 T 中那些可以赋值给 U 的类型 Extract<'a' | 'b' | 'c', 'a' | 'b'> ===> 'a'|'b'
type Extract = T extends U ? T : never;

//此类型获取函数 T 的参数类型并以元组形式返回 type MyFunction = (x: number, y: string) => void,Parameters 的结果类型是 [number, string]
type Parameters any> = T extends (...args: infer P) => any ? P : never;

4、模块化:ts支持模块化,可以将代码分割为多个模块,提高代码的可维护性和可重用性。ts的模块化使用和js的几乎一样,我们可以使用 import 和 export 关键字来导入和导出模块。

有一点不一样的,在 TypeScript 中,我们可以导入和导出类型,就像导入和导出变量或函数一样

// 导出类型
export type MyType = number;
// 导入类型
import { MyType } from './my-module';

// 默认导出类型
export default type MyType = number;
// 默认导入类型
import MyType from './my-module';

四、TypeScript和React的结合

1、在React相关的项目中引入ts很简单,首先我们在项目中安装typescript以及相关的类型定义库。有一些脚手架在安装时也会让开发者自己选择是要用ts还是js版本。安装完相关的库之后,就可以使用.tsx或者.ts来开发相关的组件和代码了。

//在组件中使用props时
type Props = {
  name: string;
  age: number;
};

const MyComponent: React.FC = ({ name, age }) => (
  
My name is {name} and I am {age} years old.
); //使用React中的hooks时 interface hooksProps{ num:number, str:string } const [hookObj, setHookObj] = useState({num:1,str:'哈哈'});

2、index.d.ts:当我们在ts项目中引入js库或在html文件直接引入js文件时,ts编译器会因为缺乏类型信息而无法正确的进行类型检查

或者我们想要声明全局变量、模块、函数、类等的类型时我们就可以在项目的根目录创建一个index.d.ts文件并使用declare关键字进行声明。

例如:我们在项目中引入了一个myLibrary 的 JavaScript 库,那么我们可以在index.d.ts 文件中声明这个库的类型:

//1、项目引入js库 index.d.ts
declare module 'myLibrary' {
  export function myFunction(arg: string): number;
}
//然后在你的 TypeScript 代码中,就可以像使用其他 TypeScript 模块一样使用 myLibrary
import { myFunction } from 'myLibrary';
let num: number = myFunction('hello');

//或 html页面直接引入js
 
    

//其他的ts代码
myLibrary.myFunction()

//2、全局类型声明 index.d.ts
declare var QRLogin: any;
//在其他ts代码中,则可以直接使用QRLogin这个变量

五、ts常见面试题

1、interface和type的区别

interface和type在都定义对象结构的类型时可以互换使用,在以下这些特定场景下用途不同:

1)扩展或实现一个类时,应该使用interface。

interface Animal {
  name: string;
  eat(): void;
}

class Dog implements Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  eat() {
    console.log(`${this.name} is eating.`);
  }
}

2)需要联合或交叉多个类型时,应该使用type。

type Cat = {
  name: string;
  meow(): void;
};

type CatOrDog = Cat | Dog;

const cat: CatOrDog = {
  name: 'Tom',
  meow() {
    console.log('Meow!');
  },
};

3)interface和type在继承或扩展已有类型时的方式不同

//interface 继承,使用extends关键字
interface Person {
  name: string;
  age: number;
}
interface Employee extends Person {
  employeeId: number;
}

//type继承,使用&运算符
type Person = {
  name: string;
  age: number;
};
type Employee = Person & {
  employeeId: number;
};

2、ts中any和unknown的区别

any和unknown都表示任意值。

有一个关键的区别是当一个变量被声明为any时,这个变量ts的类型检查,降低代码的类型安全性。当一个变量被声明为unknown类型时,它只能赋值给或被赋值为类型为unknown或any的变量。

3、ts中void和never的区别

1)never类型表示永远不会发生的类型,常用于函数的返回类型和类型推断。

2)void 类型表示没有任何类型,常用于表示函数没有返回值。

你可能感兴趣的:(typescript,ubuntu,javascript)